diff --git a/package.json b/package.json index b0cb5977a..6e2ee0125 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,7 @@ "status-bar": "file:packages/status-bar", "styleguide": "file:./packages/styleguide", "superstring": "^2.4.4", - "symbols-view": "https://codeload.github.com/atom/symbols-view/legacy.tar.gz/refs/tags/v0.118.4", + "symbols-view": "file:./packages/symbols-view", "tabs": "file:packages/tabs", "temp": "0.9.4", "text-buffer": "^13.18.6", @@ -224,7 +224,7 @@ "spell-check": "0.77.1", "status-bar": "file:./packages/status-bar", "styleguide": "file:./packages/styleguide", - "symbols-view": "0.118.4", + "symbols-view": "file:./packages/symbols-view", "tabs": "file:./packages/tabs", "timecop": "file:./packages/timecop", "tree-view": "0.229.1", diff --git a/packages/symbols-view/.eslintignore b/packages/symbols-view/.eslintignore new file mode 100644 index 000000000..c9d5b1e13 --- /dev/null +++ b/packages/symbols-view/.eslintignore @@ -0,0 +1 @@ +**/fixtures/**/*.js diff --git a/packages/symbols-view/.eslintrc.js b/packages/symbols-view/.eslintrc.js new file mode 100644 index 000000000..8c11ad1d1 --- /dev/null +++ b/packages/symbols-view/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + parser: 'babel-eslint', + extends: 'fbjs', + globals: { + atom: true + } +}; diff --git a/packages/symbols-view/.github/no-response.yml b/packages/symbols-view/.github/no-response.yml new file mode 100644 index 000000000..1c8799d13 --- /dev/null +++ b/packages/symbols-view/.github/no-response.yml @@ -0,0 +1,15 @@ +# Configuration for probot-no-response - https://github.com/probot/no-response + +# Number of days of inactivity before an issue is closed for lack of response +daysUntilClose: 28 + +# Label requiring a response +responseRequiredLabel: more-information-needed + +# Comment to post when closing an issue for lack of response. Set to `false` to disable. +closeComment: > + This issue has been automatically closed because there has been no response + to our request for more information from the original author. With only the + information that is currently in the issue, we don't have enough information + to take action. Please reach out if you have or find the answers we need so + that we can investigate further. diff --git a/packages/symbols-view/.gitignore b/packages/symbols-view/.gitignore new file mode 100644 index 000000000..3c3629e64 --- /dev/null +++ b/packages/symbols-view/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/symbols-view/.pairs b/packages/symbols-view/.pairs new file mode 100644 index 000000000..91845b111 --- /dev/null +++ b/packages/symbols-view/.pairs @@ -0,0 +1,16 @@ +pairs: + ns: Nathan Sobo; nathan + cj: Corey Johnson; cj + dg: David Graham; dgraham + ks: Kevin Sawicki; kevin + jc: Jerry Cheung; jerry + bl: Brian Lopez; brian + jp: Justin Palmer; justin + gt: Garen Torikian; garen + mc: Matt Colyer; mcolyer + bo: Ben Ogle; benogle + jr: Jason Rudolph; jasonrudolph + jl: Jessica Lord; jlord +email: + domain: github.com +#global: true diff --git a/packages/symbols-view/.travis.yml b/packages/symbols-view/.travis.yml new file mode 100644 index 000000000..20cfe5175 --- /dev/null +++ b/packages/symbols-view/.travis.yml @@ -0,0 +1,15 @@ +language: objective-c + +notifications: + email: + on_success: never + on_failure: change + +script: 'curl -s https://raw.githubusercontent.com/atom/ci/master/build-package.sh | sh' + +git: + depth: 10 + +branches: + only: + - master diff --git a/packages/symbols-view/CONTRIBUTING.md b/packages/symbols-view/CONTRIBUTING.md new file mode 100644 index 000000000..9c8ac3e5b --- /dev/null +++ b/packages/symbols-view/CONTRIBUTING.md @@ -0,0 +1 @@ +[See how you can contribute](https://github.com/pulsar-edit/.github/blob/main/CONTRIBUTING.md) diff --git a/packages/symbols-view/LICENSE.md b/packages/symbols-view/LICENSE.md new file mode 100644 index 000000000..4d231b456 --- /dev/null +++ b/packages/symbols-view/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/symbols-view/README.md b/packages/symbols-view/README.md new file mode 100644 index 000000000..fd20ed5b0 --- /dev/null +++ b/packages/symbols-view/README.md @@ -0,0 +1,16 @@ +# Symbols View package + +Display the list of functions/methods in the editor. + +If your project has a `tags`/`.tags`/`TAGS`/`.TAGS` file at the root then following are supported: + +|Command|Description|Keybinding (Linux)|Keybinding (macOS)|Keybinding (Windows)| +|-------|-----------|------------------|-----------------|--------------------| +|`symbols-view:toggle-file-symbols`|Show all symbols in current file|ctrl-r|cmd-r|ctrl-r| +|`symbols-view:toggle-project-symbols`|Show all symbols in the project|ctrl-shift-r|cmd-shift-r|ctrl-shift-r| +|`symbols-view:go-to-declaration`|Jump to the symbol under the cursor|ctrl-alt-down|cmd-alt-down|| +|`symbols-view:return-from-declaration`|Return from the jump|ctrl-alt-up|cmd-alt-up|| + +This package uses [ctags](http://ctags.sourceforge.net). + +![](https://f.cloud.github.com/assets/671378/2241860/30ef0b2e-9ce8-11e3-86e2-2c17c0885fa4.png) diff --git a/packages/symbols-view/appveyor.yml b/packages/symbols-view/appveyor.yml new file mode 100644 index 000000000..3ab50c6e5 --- /dev/null +++ b/packages/symbols-view/appveyor.yml @@ -0,0 +1,29 @@ +image: Visual Studio 2015 + +version: "{build}" + +platform: x64 + +branches: + only: + - master + +clone_depth: 10 + +skip_tags: true + +environment: + APM_TEST_PACKAGES: + + matrix: + - ATOM_CHANNEL: stable + - ATOM_CHANNEL: beta + +install: + - ps: Install-Product node 4 + +build_script: + - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/atom/ci/master/build-package.ps1')) + +test: off +deploy: off diff --git a/packages/symbols-view/keymaps/symbols-view.cson b/packages/symbols-view/keymaps/symbols-view.cson new file mode 100644 index 000000000..1014a3955 --- /dev/null +++ b/packages/symbols-view/keymaps/symbols-view.cson @@ -0,0 +1,18 @@ +'.platform-darwin atom-text-editor': + 'cmd-r': 'symbols-view:toggle-file-symbols' + 'cmd-alt-down': 'symbols-view:go-to-declaration' + 'cmd-alt-up': 'symbols-view:return-from-declaration' + +'.platform-win32 atom-text-editor': + 'ctrl-r': 'symbols-view:toggle-file-symbols' + +'.platform-linux atom-text-editor': + 'ctrl-r': 'symbols-view:toggle-file-symbols' + 'ctrl-alt-down': 'symbols-view:go-to-declaration' + 'ctrl-alt-up': 'symbols-view:return-from-declaration' + +'.platform-darwin': + 'cmd-shift-r': 'symbols-view:toggle-project-symbols' + +'.platform-win32, .platform-linux': + 'ctrl-shift-r': 'symbols-view:toggle-project-symbols' diff --git a/packages/symbols-view/lib/ctags-config b/packages/symbols-view/lib/ctags-config new file mode 100644 index 000000000..66d26e8eb --- /dev/null +++ b/packages/symbols-view/lib/ctags-config @@ -0,0 +1,198 @@ +--langdef=CoffeeScript +--langmap=CoffeeScript:.coffee +--regex-CoffeeScript=/^[ \t]*(@?[a-zA-Z$_\.0-9]+)[ \t]*(=|\:)[ \t]*(\(.*\))?[ \t]*(-|=)>/\1/f,function/ +--regex-CoffeeScript=/^[ \t]*([a-zA-Z$_0-9]+\:\:[a-zA-Z$_\.0-9]+)[ \t]*(=|\:)[ \t]*(\(.*\))?[ \t]*(-|=)>/\1/f,function/ +--regex-CoffeeScript=/^[ \t]*describe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-CoffeeScript=/^[ \t]*describe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-CoffeeScript=/^[ \t]*it[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-CoffeeScript=/^[ \t]*it[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-CoffeeScript=/^[ \t]*f+describe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/focused\: \1/f,function/ +--regex-CoffeeScript=/^[ \t]*f+describe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/focused: \1/f,function/ +--regex-CoffeeScript=/^[ \t]*f+it[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/focused: \1/f,function/ +--regex-CoffeeScript=/^[ \t]*f+it[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/focused: \1/f,function/ +--regex-CoffeeScript=/^[ \t]*xdescribe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/disabled\: \1/f,function/ +--regex-CoffeeScript=/^[ \t]*xdescribe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ +--regex-CoffeeScript=/^[ \t]*xit[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ +--regex-CoffeeScript=/^[ \t]*xit[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ +--regex-CoffeeScript=/^[ \t]*class[ \t]*([a-zA-Z$_\.0-9]+)[ \t]*/\1/f,function/ + +--langdef=ColdFusion +--langmap=ColdFusion:.cfc +--langmap=ColdFusion:+.cfm +--langmap=ColdFusion:+.cfml +--regex-ColdFusion=/(,|(;|^)[ \t]*(var|([A-Za-z_$][A-Za-z0-9_$.]*\.)*))[ \t]*([A-Za-z0-9_$]+)[ \t]*=[ \t]*function[ \t]*\(/\5/,function/ +--regex-ColdFusion=/function[ \t]+([A-Za-z0-9_$]+)[ \t]*\([^)]*\)/\1/,function/ +--regex-ColdFusion=/cffunction[ \t]+([A-Za-z0-9_$]+)[ \t]*\([^)]*\)/\1/,cffunction/ +--regex-ColdFusion=/(,|^|\*\/)[ \t]*([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*:[ \t]*function[ \t]*\(/\2/,function/ +--regex-ColdFusion=/(,|^|\*\/)[ \t]*(static[ \t]+)?(while|if|for|function|switch|with|([A-Za-z_$][A-Za-z0-9_$]+))[ \t]*\(.*\)[ \t]*\{/\2\4/,function/ +--regex-ColdFusion=/(,|^|\*\/)[ \t]*get[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*\)[ \t]*\{/get \2/,function/ +--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/ +--regex-ColdFusion=/(,|^|\*\/)[ \t]*async[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*([A-Za-z_$].+)?[ \t]*\)[ \t]*\{/\2/,function/ +--regex-ColdFusion=/component[ \t]+([A-Za-z0-9._$]+)[ \t]*/\1/c,component/ +--regex-ColdFusion=/^[ \t]*given[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*given[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*story[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*story[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*feature[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*feature[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*when[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*when[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*then[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*then[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*describe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*describe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*it[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*it[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/\1/f,function/ +--regex-ColdFusion=/^[ \t]*xdescribe[ \t]"(.+)"[ \t]*,[ \t]+[-=]>/disabled\: \1/f,function/ +--regex-ColdFusion=/^[ \t]*xdescribe[ \t]'(.+)'[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ +--regex-ColdFusion=/^[ \t]*xit[ \t]"([^"]+)"[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ +--regex-ColdFusion=/^[ \t]*xit[ \t]'([^']+)'[ \t]*,[ \t]+[-=]>/disabled: \1/f,function/ + +--langdef=Css +--langmap=Css:.css +--langmap=Css:+.less +--langmap=Css:+.scss +--regex-Css=/^[ \t]*(.+)[ \t]*\{/\1/f,function/ +--regex-Css=/^[ \t]*(.+)[ \t]*,[ \t]*$/\1/f,function/ +--regex-Css=/^[ \t]*[@$]([a-zA-Z$_][-a-zA-Z$_0-9]*)[ \t]*:/\1/f,function/ + +--langdef=Sass +--langmap=Sass:.sass +--regex-Sass=/^[ \t]*([#.]*[a-zA-Z_0-9]+)[ \t]*$/\1/f,function/ + +--langdef=Yaml +--langmap=Yaml:.yaml +--langmap=Yaml:+.yml +--regex-Yaml=/^[ \t]*([a-zA-Z_0-9 ]+)[ \t]*\:[ \t]*/\1/f,function/ + +--regex-Html=/^[ \t]*<([a-zA-Z]+)[ \t]*.*>/\1/f,function/ + +--langdef=Markdown +--langmap=Markdown:.md +--langmap=Markdown:+.markdown +--langmap=Markdown:+.mdown +--langmap=Markdown:+.mkd +--langmap=Markdown:+.mkdown +--langmap=Markdown:+.ron +--regex-Markdown=/^#+[ \t]*([^#]+)/\1/f,function/ + +--langdef=Json +--langmap=Json:.json +--regex-Json=/^[ \t]*"([^"]+)"[ \t]*\:/\1/f,function/ + +--langdef=Cson +--langmap=Cson:.cson +--langmap=Cson:+.gyp +--regex-Cson=/^[ \t]*'([^']+)'[ \t]*\:/\1/f,function/ +--regex-Cson=/^[ \t]*"([^"]+)"[ \t]*\:/\1/f,function/ +--regex-Cson=/^[ \t]*([^'"]+)[ \t]*\:/\1/f,function/ + +--langmap=C++:+.mm + +--langmap=Ruby:+(Rakefile) + +--langmap=Php:+.module + +--langdef=Go +--langmap=Go:.go +--regex-Go=/func([ \t]+\([^)]+\))?[ \t]+([a-zA-Z0-9_]+)/\2/f,func/ +--regex-Go=/var[ \t]+([a-zA-Z_][a-zA-Z0-9_]*)/\1/v,var/ +--regex-Go=/type[ \t]+([a-zA-Z_][a-zA-Z0-9_]*)/\1/t,type/ + +--langdef=Capnp +--langmap=Capnp:.capnp +--regex-Capnp=/struct[ \t]+([A-Za-z]+)/\1/s,struct/ +--regex-Capnp=/enum[ \t]+([A-Za-z]+)/\1/e,enum/ +--regex-Capnp=/using[ \t]+([A-Za-z]+)[ \t]+=[ \t]+import/\1/u,using/ +--regex-Capnp=/const[ \t]+([A-Za-z]+)/\1/c,const/ + +--langmap=perl:+.pod +--regex-perl=/with[ \t]+([^;]+)[ \t]*?;/\1/w,role,roles/ +--regex-perl=/extends[ \t]+['"]([^'"]+)['"][ \t]*?;/\1/e,extends/ +--regex-perl=/use[ \t]+base[ \t]+['"]([^'"]+)['"][ \t]*?;/\1/e,extends/ +--regex-perl=/use[ \t]+parent[ \t]+['"]([^'"]+)['"][ \t]*?;/\1/e,extends/ +--regex-perl=/Mojo::Base[ \t]+['"]([^'"]+)['"][ \t]*?;/\1/e,extends/ +--regex-perl=/^[ \t]*?use[ \t]+([^;]+)[ \t]*?;/\1/u,use,uses/ +--regex-perl=/^[ \t]*?require[ \t]+((\w|\:)+)/\1/r,require,requires/ +--regex-perl=/^[ \t]*?has[ \t]+['"]?(\w+)['"]?/\1/a,attribute,attributes/ +--regex-perl=/^[ \t]*?\*(\w+)[ \t]*?=/\1/a,alias,aliases/ +--regex-perl=/->helper\([ \t]?['"]?(\w+)['"]?/\1/h,helper,helpers/ +--regex-perl=/^[ \t]*?our[ \t]*?[\$@%](\w+)/\1/o,our,ours/ +--regex-perl=/^\=head1[ \t]+(.+)/\1/p,pod,Plain Old Documentation/ +--regex-perl=/^\=head2[ \t]+(.+)/-- \1/p,pod,Plain Old Documentation/ +--regex-perl=/^\=head[3-5][ \t]+(.+)/---- \1/p,pod,Plain Old Documentation/ + +--regex-JavaScript=/(,|(;|^)[ \t]*(var|let|([A-Za-z_$][A-Za-z0-9_$.]*\.)*))[ \t]*([A-Za-z0-9_$]+)[ \t]*=[ \t]*function[ \t]*\(/\5/,function/ +--regex-JavaScript=/function[ \t]+([A-Za-z0-9_$]+)[ \t]*\([^)]*\)/\1/,function/ +--regex-JavaScript=/(,|^|\*\/)[ \t]*([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*:[ \t]*function[ \t]*\(/\2/,function/ +--regex-JavaScript=/(,|^|\*\/)[ \t]*(static[ \t]+)?(while|if|for|function|switch|with|([A-Za-z_$][A-Za-z0-9_$]+))[ \t]*\(.*\)[ \t]*\{/\2\4/,function/ +--regex-JavaScript=/(,|^|\*\/)[ \t]*get[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*\)[ \t]*\{/get \2/,function/ +--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/ +--regex-JavaScript=/(,|^|\*\/)[ \t]*async[ \t]+([A-Za-z_$][A-Za-z0-9_$]+)[ \t]*\([ \t]*([A-Za-z_$].+)?[ \t]*\)[ \t]*\{/\2/,function/ +--regex-JavaScript=/class[ \t]+([A-Za-z0-9._$]+)[ \t]*/\1/c,class/ +--regex-JavaScript=/^[ \t]*describe\("([^"]+)"[ \t]*,/\1/f,function/ +--regex-JavaScript=/^[ \t]*describe\('([^']+)'[ \t]*,/\1/f,function/ +--regex-JavaScript=/^[ \t]*it\("([^"]+)"[ \t]*,/\1/f,function/ +--regex-JavaScript=/^[ \t]*it\('([^']+)'[ \t]*,/\1/f,function/ +--regex-JavaScript=/^[ \t]*f+describe\('([^']+)'[ \t]*,/focused: \1/f,function/ +--regex-JavaScript=/^[ \t]*f+describe\("([^"]+)"[ \t]*,/focused: \1/f,function/ +--regex-JavaScript=/^[ \t]*f+it\('([^']+)'[ \t]*,/focused: \1/f,function/ +--regex-JavaScript=/^[ \t]*f+it\("([^"]+)"[ \t]*,/focused: \1/f,function/ +--regex-JavaScript=/^[ \t]*xdescribe\('([^']+)'[ \t]*,/disabled: \1/f,function/ +--regex-JavaScript=/^[ \t]*xdescribe\("([^"]+)"[ \t]*,/disabled: \1/f,function/ +--regex-JavaScript=/^[ \t]*xit\('([^']+)'[ \t]*,/disabled: \1/f,function/ +--regex-JavaScript=/^[ \t]*xit\("([^"]+)"[ \t]*,/disabled: \1/f,function/ + +--langdef=haxe +--langmap=haxe:.hx +--regex-haxe=/^package[ \t]+([A-Za-z0-9_.]+)/\1/p,package/ +--regex-haxe=/^[ \t]*[(@:macro|private|public|static|override|inline|dynamic)( \t)]*function[ \t]+([A-Za-z0-9_]+)/\1/f,function/ +--regex-haxe=/^[ \t]*([private|public|static|protected|inline][ \t]*)+var[ \t]+([A-Za-z0-9_]+)/\2/v,variable/ +--regex-haxe=/^[ \t]*package[ \t]*([A-Za-z0-9_]+)/\1/p,package/ +--regex-haxe=/^[ \t]*(extern[ \t]*|@:native\([^)]*\)[ \t]*)*class[ \t]+([A-Za-z0-9_]+)[ \t]*[^\{]*/\2/c,class/ +--regex-haxe=/^[ \t]*(extern[ \t]+)?interface[ \t]+([A-Za-z0-9_]+)/\2/i,interface/ +--regex-haxe=/^[ \t]*typedef[ \t]+([A-Za-z0-9_]+)/\1/t,typedef/ +--regex-haxe=/^[ \t]*enum[ \t]+([A-Za-z0-9_]+)/\1/t,typedef/ +--regex-haxe=/^[ \t]*+([A-Za-z0-9_]+)(;|\([^)]*:[^)]*\))/\1/t,enum_field/ + +--langdef=Elixir +--langmap=Elixir:.ex.exs +--regex-Elixir=/^[ \t]*def(p?)[ \t]+([a-z_][a-zA-Z0-9_?!]*)/\2/f,functions,functions (def ...)/ +--regex-Elixir=/^[ \t]*defcallback[ \t]+([a-z_][a-zA-Z0-9_?!]*)/\1/c,callbacks,callbacks (defcallback ...)/ +--regex-Elixir=/^[ \t]*defdelegate[ \t]+([a-z_][a-zA-Z0-9_?!]*)/\1/d,delegates,delegates (defdelegate ...)/ +--regex-Elixir=/^[ \t]*defexception[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/e,exceptions,exceptions (defexception ...)/ +--regex-Elixir=/^[ \t]*defimpl[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/i,implementations,implementations (defimpl ...)/ +--regex-Elixir=/^[ \t]*defmacro(p?)[ \t]+([a-z_][a-zA-Z0-9_?!]*)\(/\2/a,macros,macros (defmacro ...)/ +--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")/ +--regex-Elixir=/^[ \t]*defmodule[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/m,modules,modules (defmodule ...)/ +--regex-Elixir=/^[ \t]*defprotocol[ \t]+([A-Z][a-zA-Z0-9_]*\.)*([A-Z][a-zA-Z0-9_?!]*)/\2/p,protocols,protocols (defprotocol...)/ +--regex-Elixir=/^[ \t]*Record\.defrecord[ \t]+:([a-zA-Z0-9_]+)/\1/r,records,records (defrecord...)/ + +--langdef=Nim +--langmap=Nim:.nim +--regex-Nim=/^[\t\s]*proc\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/f,function/ +--regex-Nim=/^[\t\s]*iterator\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/i,iterator/ +--regex-Nim=/^[\t\s]*macro\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/m,macro/ +--regex-Nim=/^[\t\s]*method\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/h,method/ +--regex-Nim=/^[\t\s]*template\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/t,generics/ +--regex-Nim=/^[\t\s]*converter\s+([_A-Za-z0-9]+)\**(\[\w+(\:\s+\w+)?\])?\s*\(/\1/c,converter/ + +--langdef=Fountain +--langmap=Fountain:.fountain +--langmap=Fountain:+.ftn +--regex-Fountain=/^(([iI][nN][tT]|[eE][xX][tT]|[^\w][eE][sS][tT]|\.|[iI]\.?\/[eE]\.?)([^\n]+))/\1/f,function/ + +--langdef=Julia +--langmap=Julia:.jl +--regex-Julia=/^[ \t]*(function|macro|abstract|type|typealias|immutable)[ \t]+([^ \t({[]+).*$/\2/f,function/ +--regex-Julia=/^[ \t]*(([^@#$ \t({[]+)|\(([^@#$ \t({[]+)\)|\((\$)\))[ \t]*(\{.*\})?[ \t]*\([^#]*\)[ \t]*=([^=].*$|$)/\2\3\4/f,function/ + +--langdef=Latex +--langmap=latex:.tex +--regex-latex=/\\label\{([^}]*)\}/\1/l,label/ +--regex-latex=/\\section\{([^}]*)\}/\1/s,section/ +--regex-latex=/\\subsection\{([^}]*)\}/\1/t,subsection/ +--regex-latex=/\\subsubsection\{([^}]*)\}/\1/u,subsubsection/ +--regex-latex=/\\section\*\{([^}]*)\}/\1/s,section/ +--regex-latex=/\\subsection\*\{([^}]*)\}/\1/t,subsection/ +--regex-latex=/\\subsubsection\*\{([^}]*)\}/\1/u,subsubsection/ diff --git a/packages/symbols-view/lib/file-view.js b/packages/symbols-view/lib/file-view.js new file mode 100644 index 000000000..18c190f3a --- /dev/null +++ b/packages/symbols-view/lib/file-view.js @@ -0,0 +1,146 @@ +/** @babel */ + +import { CompositeDisposable } from 'atom'; +import SymbolsView from './symbols-view'; +import TagGenerator from './tag-generator'; +import { match } from 'fuzzaldrin'; + +export default class FileView extends SymbolsView { + constructor(stack) { + super(stack); + this.cachedTags = {}; + this.watchedEditors = new WeakSet(); + + this.editorsSubscription = atom.workspace.observeTextEditors(editor => { + if (this.watchedEditors.has(editor)) return; + + const removeFromCache = () => { + delete this.cachedTags[editor.getPath()]; + }; + const editorSubscriptions = new CompositeDisposable(); + editorSubscriptions.add(editor.onDidChangeGrammar(removeFromCache)); + editorSubscriptions.add(editor.onDidSave(removeFromCache)); + editorSubscriptions.add(editor.onDidChangePath(removeFromCache)); + editorSubscriptions.add(editor.getBuffer().onDidReload(removeFromCache)); + editorSubscriptions.add(editor.getBuffer().onDidDestroy(removeFromCache)); + editor.onDidDestroy(() => { + this.watchedEditors.delete(editor); + editorSubscriptions.dispose(); + }); + + this.watchedEditors.add(editor); + }); + } + + destroy() { + this.editorsSubscription.dispose(); + return super.destroy(); + } + + elementForItem({position, name}) { + // Style matched characters in search results + const matches = match(name, this.selectListView.getFilterQuery()); + + const li = document.createElement('li'); + li.classList.add('two-lines'); + + const primaryLine = document.createElement('div'); + primaryLine.classList.add('primary-line'); + primaryLine.appendChild(SymbolsView.highlightMatches(this, name, matches)); + li.appendChild(primaryLine); + + const secondaryLine = document.createElement('div'); + secondaryLine.classList.add('secondary-line'); + secondaryLine.textContent = `Line ${position.row + 1}`; + li.appendChild(secondaryLine); + + return li; + } + + didChangeSelection(item) { + if (atom.config.get('symbols-view.quickJumpToFileSymbol') && item) { + this.openTag(item); + } + } + + async didCancelSelection() { + await this.cancel(); + const editor = this.getEditor(); + if (this.initialState && editor) { + this.deserializeEditorState(editor, this.initialState); + } + this.initialState = null; + } + + async toggle() { + if (this.panel.isVisible()) { + await this.cancel(); + } + const filePath = this.getPath(); + if (filePath) { + const editor = this.getEditor(); + if (atom.config.get('symbols-view.quickJumpToFileSymbol') && editor) { + this.initialState = this.serializeEditorState(editor); + } + this.populate(filePath); + this.attach(); + } + } + + serializeEditorState(editor) { + const editorElement = atom.views.getView(editor); + const scrollTop = editorElement.getScrollTop(); + + return { + bufferRanges: editor.getSelectedBufferRanges(), + scrollTop, + }; + } + + deserializeEditorState(editor, {bufferRanges, scrollTop}) { + const editorElement = atom.views.getView(editor); + + editor.setSelectedBufferRanges(bufferRanges); + editorElement.setScrollTop(scrollTop); + } + + getEditor() { + return atom.workspace.getActiveTextEditor(); + } + + getPath() { + if (this.getEditor()) { + return this.getEditor().getPath(); + } + return undefined; + } + + getScopeName() { + if (this.getEditor() && this.getEditor().getGrammar()) { + return this.getEditor().getGrammar().scopeName; + } + return undefined; + } + + async populate(filePath) { + const tags = this.cachedTags[filePath]; + if (tags) { + await this.selectListView.update({items: tags}); + } else { + await this.selectListView.update({ + items: [], + loadingMessage: 'Generating symbols\u2026', + }); + await this.selectListView.update({ + items: await this.generateTags(filePath), + loadingMessage: null, + }); + } + } + + async generateTags(filePath) { + const generator = new TagGenerator(filePath, this.getScopeName()); + this.cachedTags[filePath] = await generator.generate(); + return this.cachedTags[filePath]; + } +} diff --git a/packages/symbols-view/lib/get-tags-file.js b/packages/symbols-view/lib/get-tags-file.js new file mode 100644 index 000000000..e7f617714 --- /dev/null +++ b/packages/symbols-view/lib/get-tags-file.js @@ -0,0 +1,20 @@ +/** @babel */ + +import path from 'path'; +import fs from 'fs-plus'; + +const files = ['tags', 'TAGS', '.tags', '.TAGS', path.join('.git', 'tags'), path.join('.git', 'TAGS')]; +export default function(directoryPath) { + if (!directoryPath) { + return undefined; + } + + for (const file of files) { + const tagsFile = path.join(directoryPath, file); + if (fs.isFileSync(tagsFile)) { + return tagsFile; + } + } + + return undefined; +} diff --git a/packages/symbols-view/lib/go-back-view.js b/packages/symbols-view/lib/go-back-view.js new file mode 100644 index 000000000..a5e533c89 --- /dev/null +++ b/packages/symbols-view/lib/go-back-view.js @@ -0,0 +1,28 @@ +/** @babel */ + +import SymbolsView from './symbols-view'; + +export default class GoBackView extends SymbolsView { + toggle() { + const previousTag = this.stack.pop(); + if (!previousTag) { + return; + } + + const restorePosition = () => { + if (previousTag.position) { + this.moveToPosition(previousTag.position, false); + } + }; + + const previousEditor = atom.workspace.getTextEditors().find(e => e.id === previousTag.editorId); + + if (previousEditor) { + const pane = atom.workspace.paneForItem(previousEditor); + pane.setActiveItem(previousEditor); + restorePosition(); + } else if (previousTag.file) { + atom.workspace.open(previousTag.file).then(restorePosition); + } + } +} diff --git a/packages/symbols-view/lib/go-to-view.js b/packages/symbols-view/lib/go-to-view.js new file mode 100644 index 000000000..50f2aa6c7 --- /dev/null +++ b/packages/symbols-view/lib/go-to-view.js @@ -0,0 +1,65 @@ +/** @babel */ + +import path from 'path'; +import SymbolsView from './symbols-view'; +import TagReader from './tag-reader'; + +export default class GoToView extends SymbolsView { + toggle() { + if (this.panel.isVisible()) { + this.cancel(); + } else { + this.populate(); + } + } + + detached() { + if (this.resolveFindTagPromise) { + this.resolveFindTagPromise([]); + } + } + + findTag(editor) { + if (this.resolveFindTagPromise) { + this.resolveFindTagPromise([]); + } + + return new Promise((resolve, reject) => { + this.resolveFindTagPromise = resolve; + TagReader.find(editor, (error, matches) => { + if (!matches) { + matches = []; + } + if (error) { + return reject(error); + } else { + return resolve(matches); + } + }); + }); + } + + async populate() { + let editor = atom.workspace.getActiveTextEditor(); + if (!editor) { + return; + } + + this.findTag(editor).then(async matches => { + let tags = []; + for (let match of Array.from(matches)) { + let position = this.getTagLine(match); + if (!position) { continue; } + match.name = path.basename(match.file); + tags.push(match); + } + + if (tags.length === 1) { + this.openTag(tags[0]); + } else if (tags.length > 0) { + await this.selectListView.update({items: tags}); + this.attach(); + } + }); + } +} diff --git a/packages/symbols-view/lib/load-tags-handler.js b/packages/symbols-view/lib/load-tags-handler.js new file mode 100644 index 000000000..692aff39c --- /dev/null +++ b/packages/symbols-view/lib/load-tags-handler.js @@ -0,0 +1,25 @@ +/** @babel */ +/* global emit*/ + +import async from 'async'; +import ctags from 'ctags'; +import getTagsFile from './get-tags-file'; + +export default function(directoryPaths) { + return async.each( + directoryPaths, + (directoryPath, done) => { + let tagsFilePath = getTagsFile(directoryPath); + if (!tagsFilePath) { return done(); } + + let stream = ctags.createReadStream(tagsFilePath); + stream.on('data', function(tags) { + for (const tag of Array.from(tags)) { tag.directory = directoryPath; } + return emit('tags', tags); + }); + stream.on('end', done); + return stream.on('error', done); + } + , this.async() + ); +} diff --git a/packages/symbols-view/lib/main.js b/packages/symbols-view/lib/main.js new file mode 100644 index 000000000..e18b50e5b --- /dev/null +++ b/packages/symbols-view/lib/main.js @@ -0,0 +1,93 @@ +/** @babel */ + +export default { + activate() { + this.stack = []; + + this.workspaceSubscription = atom.commands.add('atom-workspace', { + 'symbols-view:toggle-project-symbols': () => { + this.createProjectView().toggle(); + }, + }); + + this.editorSubscription = atom.commands.add('atom-text-editor', { + 'symbols-view:toggle-file-symbols': () => { + this.createFileView().toggle(); + }, + 'symbols-view:go-to-declaration': () => { + this.createGoToView().toggle(); + }, + 'symbols-view:return-from-declaration': () => { + this.createGoBackView().toggle(); + }, + }); + }, + + deactivate() { + if (this.fileView != null) { + this.fileView.destroy(); + this.fileView = null; + } + + if (this.projectView != null) { + this.projectView.destroy(); + this.projectView = null; + } + + if (this.goToView != null) { + this.goToView.destroy(); + this.goToView = null; + } + + if (this.goBackView != null) { + this.goBackView.destroy(); + this.goBackView = null; + } + + if (this.workspaceSubscription != null) { + this.workspaceSubscription.dispose(); + this.workspaceSubscription = null; + } + + if (this.editorSubscription != null) { + this.editorSubscription.dispose(); + this.editorSubscription = null; + } + }, + + createFileView() { + if (this.fileView) { + return this.fileView; + } + const FileView = require('./file-view'); + this.fileView = new FileView(this.stack); + return this.fileView; + }, + + createProjectView() { + if (this.projectView) { + return this.projectView; + } + const ProjectView = require('./project-view'); + this.projectView = new ProjectView(this.stack); + return this.projectView; + }, + + createGoToView() { + if (this.goToView) { + return this.goToView; + } + const GoToView = require('./go-to-view'); + this.goToView = new GoToView(this.stack); + return this.goToView; + }, + + createGoBackView() { + if (this.goBackView) { + return this.goBackView; + } + const GoBackView = require('./go-back-view'); + this.goBackView = new GoBackView(this.stack); + return this.goBackView; + }, +}; diff --git a/packages/symbols-view/lib/project-view.js b/packages/symbols-view/lib/project-view.js new file mode 100644 index 000000000..e0605cad1 --- /dev/null +++ b/packages/symbols-view/lib/project-view.js @@ -0,0 +1,105 @@ +/** @babel */ + +import { CompositeDisposable, File } from 'atom'; +import humanize from 'humanize-plus'; +import SymbolsView from './symbols-view'; +import TagReader from './tag-reader'; +import getTagsFile from './get-tags-file'; + +export default class ProjectView extends SymbolsView { + constructor(stack) { + super(stack, 'Project has no tags file or it is empty', 10); + this.reloadTags = true; + } + + destroy() { + this.stopTask(); + this.unwatchTagsFiles(); + return super.destroy(); + } + + toggle() { + if (this.panel.isVisible()) { + this.cancel(); + } else { + this.populate(); + this.attach(); + } + } + + async populate() { + if (this.tags) { + await this.selectListView.update({items: this.tags}); + } + + if (this.reloadTags) { + this.reloadTags = false; + this.startTask(); + + if (this.tags) { + await this.selectListView.update({ + loadingMessage: 'Reloading project symbols\u2026', + }); + } else { + await this.selectListView.update({ + loadingMessage: 'Loading project symbols\u2026', + loadingBadge: 0, + }); + let tagsRead = 0; + this.loadTagsTask.on('tags', tags => { + tagsRead += tags.length; + this.selectListView.update({loadingBadge: humanize.intComma(tagsRead)}); + }); + } + } + } + + stopTask() { + if (this.loadTagsTask) { + this.loadTagsTask.terminate(); + } + } + + startTask() { + this.stopTask(); + + this.loadTagsTask = TagReader.getAllTags(tags => { + this.tags = tags; + this.reloadTags = this.tags.length === 0; + this.selectListView.update({ + loadingMessage: null, + loadingBadge: null, + items: this.tags, + }); + }); + + this.watchTagsFiles(); + } + + watchTagsFiles() { + this.unwatchTagsFiles(); + + this.tagsFileSubscriptions = new CompositeDisposable(); + let reloadTags = () => { + this.reloadTags = true; + this.watchTagsFiles(); + }; + + for (const projectPath of Array.from(atom.project.getPaths())) { + const tagsFilePath = getTagsFile(projectPath); + if (tagsFilePath) { + const tagsFile = new File(tagsFilePath); + this.tagsFileSubscriptions.add(tagsFile.onDidChange(reloadTags)); + this.tagsFileSubscriptions.add(tagsFile.onDidDelete(reloadTags)); + this.tagsFileSubscriptions.add(tagsFile.onDidRename(reloadTags)); + } + } + } + + unwatchTagsFiles() { + if (this.tagsFileSubscriptions) { + this.tagsFileSubscriptions.dispose(); + } + this.tagsFileSubscriptions = null; + } +} diff --git a/packages/symbols-view/lib/symbols-view.js b/packages/symbols-view/lib/symbols-view.js new file mode 100644 index 000000000..17cf42312 --- /dev/null +++ b/packages/symbols-view/lib/symbols-view.js @@ -0,0 +1,224 @@ +/** @babel */ + +import path from 'path'; +import { Point } from 'atom'; +import SelectListView from 'atom-select-list'; +import fs from 'fs-plus'; +import { match } from 'fuzzaldrin'; + +export default class SymbolsView { + static highlightMatches(context, name, matches, offsetIndex) { + if (!offsetIndex) { + offsetIndex = 0; + } + let lastIndex = 0; + let matchedChars = []; // Build up a set of matched chars to be more semantic + const fragment = document.createDocumentFragment(); + + for (let matchIndex of Array.from(matches)) { + matchIndex -= offsetIndex; + if (matchIndex < 0) { + continue; // If marking up the basename, omit name matches + } + const unmatched = name.substring(lastIndex, matchIndex); + if (unmatched) { + if (matchedChars.length) { + const span = document.createElement('span'); + span.classList.add('character-match'); + span.textContent = matchedChars.join(''); + fragment.appendChild(span); + } + matchedChars = []; + fragment.appendChild(document.createTextNode(unmatched)); + } + matchedChars.push(name[matchIndex]); + lastIndex = matchIndex + 1; + } + + if (matchedChars.length) { + const span = document.createElement('span'); + span.classList.add('character-match'); + span.textContent = matchedChars.join(''); + fragment.appendChild(span); + } + + // Remaining characters are plain text + fragment.appendChild(document.createTextNode(name.substring(lastIndex))); + + return fragment; + } + + constructor(stack, emptyMessage = 'No symbols found', maxResults = null) { + this.stack = stack; + this.selectListView = new SelectListView({ + maxResults, + emptyMessage, + items: [], + filterKeyForItem: (item) => item.name, + elementForItem: this.elementForItem.bind(this), + didChangeSelection: this.didChangeSelection.bind(this), + didConfirmSelection: this.didConfirmSelection.bind(this), + didConfirmEmptySelection: this.didConfirmEmptySelection.bind(this), + didCancelSelection: this.didCancelSelection.bind(this), + }); + this.element = this.selectListView.element; + this.element.classList.add('symbols-view'); + this.panel = atom.workspace.addModalPanel({item: this, visible: false}); + } + + async destroy() { + await this.cancel(); + this.panel.destroy(); + return this.selectListView.destroy(); + } + + getFilterKey() { + return 'name'; + } + + elementForItem({position, name, file, directory}) { + // Style matched characters in search results + const matches = match(name, this.selectListView.getFilterQuery()); + + if (atom.project.getPaths().length > 1) { + file = path.join(path.basename(directory), file); + } + + const li = document.createElement('li'); + li.classList.add('two-lines'); + + const primaryLine = document.createElement('div'); + primaryLine.classList.add('primary-line'); + if (position) { + primaryLine.textContent = `${name}:${position.row + 1}`; + } else { + primaryLine.appendChild(SymbolsView.highlightMatches(this, name, matches)); + } + li.appendChild(primaryLine); + + const secondaryLine = document.createElement('div'); + secondaryLine.classList.add('secondary-line'); + secondaryLine.textContent = file; + li.appendChild(secondaryLine); + + return li; + } + + async cancel() { + if (!this.isCanceling) { + this.isCanceling = true; + await this.selectListView.update({items: []}); + this.panel.hide(); + if (this.previouslyFocusedElement) { + this.previouslyFocusedElement.focus(); + this.previouslyFocusedElement = null; + } + this.isCanceling = false; + } + } + + didCancelSelection() { + this.cancel(); + } + + didConfirmEmptySelection() { + this.cancel(); + } + + async didConfirmSelection(tag) { + if (tag.file && !fs.isFileSync(path.join(tag.directory, tag.file))) { + await this.selectListView.update({errorMessage: 'Selected file does not exist'}); + setTimeout(() => { + this.selectListView.update({errorMessage: null}); + }, 2000); + } else { + await this.cancel(); + this.openTag(tag); + } + } + + didChangeSelection(tag) { + // no-op + } + + openTag(tag) { + const editor = atom.workspace.getActiveTextEditor(); + let previous; + if (editor) { + previous = { + editorId: editor.id, + position: editor.getCursorBufferPosition(), + file: editor.getURI(), + }; + } + + let {position} = tag; + if (!position) { position = this.getTagLine(tag); } + if (tag.file) { + atom.workspace.open(path.join(tag.directory, tag.file)).then(() => { + if (position) { + return this.moveToPosition(position); + } + return undefined; + }); + } else if (position && previous && !previous.position.isEqual(position)) { + this.moveToPosition(position); + } + + this.stack.push(previous); + } + + moveToPosition(position, beginningOfLine) { + const editor = atom.workspace.getActiveTextEditor(); + if (beginningOfLine == null) { + beginningOfLine = true; + } + if (editor) { + editor.setCursorBufferPosition(position, {autoscroll: false}); + if (beginningOfLine) { + editor.moveToFirstCharacterOfLine(); + } + editor.scrollToCursorPosition({center: true}); + } + } + + attach() { + this.previouslyFocusedElement = document.activeElement; + this.panel.show(); + this.selectListView.reset(); + this.selectListView.focus(); + } + + getTagLine(tag) { + if (!tag) { + return undefined; + } + + if (tag.lineNumber) { + return new Point(tag.lineNumber - 1, 0); + } + + // Remove leading /^ and trailing $/ + if (!tag.pattern) { + return undefined; + } + const pattern = tag.pattern.replace(/(^\/\^)|(\$\/$)/g, '').trim(); + + if (!pattern) { + return undefined; + } + const file = path.join(tag.directory, tag.file); + if (!fs.isFileSync(file)) { + return undefined; + } + const iterable = fs.readFileSync(file, 'utf8').split('\n'); + for (let index = 0; index < iterable.length; index++) { + let line = iterable[index]; + if (pattern === line.trim()) { + return new Point(index, 0); + } + } + + return undefined; + } +} diff --git a/packages/symbols-view/lib/tag-generator.js b/packages/symbols-view/lib/tag-generator.js new file mode 100644 index 000000000..d07534b8c --- /dev/null +++ b/packages/symbols-view/lib/tag-generator.js @@ -0,0 +1,128 @@ +/** @babel */ + +import { BufferedProcess, Point } from 'atom'; +import path from 'path'; +import fs from 'fs-plus'; + +export default class TagGenerator { + constructor(path1, scopeName) { + this.path = path1; + this.scopeName = scopeName; + } + + getPackageRoot() { + const {resourcePath} = atom.getLoadSettings(); + const currentFileWasRequiredFromSnapshot = !fs.isAbsolute(__dirname); + const packageRoot = currentFileWasRequiredFromSnapshot + ? path.join(resourcePath, 'node_modules', 'symbols-view') + : path.resolve(__dirname, '..'); + + if (path.extname(resourcePath) === '.asar' && packageRoot.indexOf(resourcePath) === 0) { + return path.join(`${resourcePath}.unpacked`, 'node_modules', 'symbols-view'); + } else { + return packageRoot; + } + } + + parseTagLine(line) { + let sections = line.split('\t'); + if (sections.length > 3) { + return { + position: new Point(parseInt(sections[2], 10) - 1), + name: sections[0], + }; + } + return null; + } + + getLanguage() { + if (['.cson', '.gyp'].includes(path.extname(this.path))) { + return 'Cson'; + } + + switch (this.scopeName) { + case 'source.c': return 'C'; + case 'source.cpp': return 'C++'; + case 'source.clojure': return 'Lisp'; + case 'source.capnp': return 'Capnp'; + case 'source.cfscript': return 'ColdFusion'; + case 'source.cfscript.embedded': return 'ColdFusion'; + case 'source.coffee': return 'CoffeeScript'; + case 'source.css': return 'Css'; + case 'source.css.less': return 'Css'; + case 'source.css.scss': return 'Css'; + case 'source.elixir': return 'Elixir'; + case 'source.fountain': return 'Fountain'; + case 'source.gfm': return 'Markdown'; + case 'source.go': return 'Go'; + case 'source.java': return 'Java'; + case 'source.js': return 'JavaScript'; + case 'source.js.jsx': return 'JavaScript'; + case 'source.jsx': return 'JavaScript'; + case 'source.json': return 'Json'; + case 'source.julia': return 'Julia'; + case 'source.makefile': return 'Make'; + case 'source.objc': return 'C'; + case 'source.objcpp': return 'C++'; + case 'source.python': return 'Python'; + case 'source.ruby': return 'Ruby'; + case 'source.sass': return 'Sass'; + case 'source.yaml': return 'Yaml'; + case 'text.html': return 'Html'; + case 'text.html.php': return 'Php'; + case 'text.tex.latex': return 'Latex'; + case 'text.html.cfml': return 'ColdFusion'; + } + return undefined; + } + + generate() { + let tags = {}; + const packageRoot = this.getPackageRoot(); + const command = path.join(packageRoot, 'vendor', `ctags-${process.platform}`); + const defaultCtagsFile = path.join(packageRoot, 'lib', 'ctags-config'); + const args = [`--options=${defaultCtagsFile}`, '--fields=+KS']; + + if (atom.config.get('symbols-view.useEditorGrammarAsCtagsLanguage')) { + const language = this.getLanguage(); + if (language) { + args.push(`--language-force=${language}`); + } + } + + args.push('-nf', '-', this.path); + + return new Promise((resolve) => { + let result, tag; + return new BufferedProcess({ + command: command, + args: args, + stdout: (lines) => { + return (() => { + result = []; + for (const line of Array.from(lines.split('\n'))) { + let item; + if (tag = this.parseTagLine(line)) { + item = tags[tag.position.row] ? tags[tag.position.row] : (tags[tag.position.row] = tag); + } + result.push(item); + } + return result; + })(); + }, + stderr() {}, + exit() { + tags = ((() => { + result = []; + for (const row in tags) { + tag = tags[row]; + result.push(tag); + } + return result; + })()); + return resolve(tags); + }, + }); + }); + } +} diff --git a/packages/symbols-view/lib/tag-reader.js b/packages/symbols-view/lib/tag-reader.js new file mode 100644 index 000000000..07ed8ab93 --- /dev/null +++ b/packages/symbols-view/lib/tag-reader.js @@ -0,0 +1,124 @@ +/** @babel */ + +import { Task } from 'atom'; +import ctags from 'ctags'; +import async from 'async'; +import getTagsFile from './get-tags-file'; +import _ from 'underscore-plus'; + +let handlerPath = require.resolve('./load-tags-handler'); + +let wordAtCursor = (text, cursorIndex, wordSeparator, noStripBefore) => { + const beforeCursor = text.slice(0, cursorIndex); + const afterCursor = text.slice(cursorIndex); + const beforeCursorWordBegins = noStripBefore ? 0 : beforeCursor.lastIndexOf(wordSeparator) + 1; + let afterCursorWordEnds = afterCursor.indexOf(wordSeparator); + if (afterCursorWordEnds === -1) { + afterCursorWordEnds = afterCursor.length; + } + return beforeCursor.slice(beforeCursorWordBegins) + afterCursor.slice(0, afterCursorWordEnds); +}; + +export default { + find(editor, callback) { + let symbol; + const symbols = []; + + if (symbol = editor.getSelectedText()) { + symbols.push(symbol); + } + + if (!symbols.length) { + let nonWordCharacters; + const cursor = editor.getLastCursor(); + const cursorPosition = cursor.getBufferPosition(); + const scope = cursor.getScopeDescriptor(); + const rubyScopes = scope.getScopesArray().filter(s => /^source\.ruby($|\.)/.test(s)); + + const wordRegExp = rubyScopes.length ? + (nonWordCharacters = atom.config.get('editor.nonWordCharacters', {scope}), + // Allow special handling for fully-qualified ruby constants + nonWordCharacters = nonWordCharacters.replace(/:/g, ''), + new RegExp(`[^\\s${_.escapeRegExp(nonWordCharacters)}]+([!?]|\\s*=>?)?|[<=>]+`, 'g')) + : + cursor.wordRegExp(); + + const addSymbol = (symbol) => { + if (rubyScopes.length) { + // Normalize assignment syntax + if (/\s+=?$/.test(symbol)) { symbols.push(symbol.replace(/\s+=$/, '=')); } + // Strip away assignment & hashrocket syntax + symbols.push(symbol.replace(/\s+=>?$/, '')); + } else { + symbols.push(symbol); + } + }; + + // Can't use `getCurrentWordBufferRange` here because we want to select + // the last match of the potential 2 matches under cursor. + editor.scanInBufferRange(wordRegExp, cursor.getCurrentLineBufferRange(), ({range, match}) => { + if (range.containsPoint(cursorPosition)) { + symbol = match[0]; + if (rubyScopes.length && symbol.indexOf(':') > -1) { + const cursorWithinSymbol = cursorPosition.column - range.start.column; + // Add fully-qualified ruby constant up until the cursor position + addSymbol(wordAtCursor(symbol, cursorWithinSymbol, ':', true)); + // Additionally, also look up the bare word under cursor + addSymbol(wordAtCursor(symbol, cursorWithinSymbol, ':')); + } else { + addSymbol(symbol); + } + } + }); + } + + if (!symbols.length) { + process.nextTick(() => { + callback(null, []); + }); + } + + async.map(atom.project.getPaths(), (projectPath, done) => { + const tagsFile = getTagsFile(projectPath); + let foundTags = []; + let foundErr = null; + const detectCallback = () => { + done(foundErr, foundTags); + }; + if (!tagsFile) { + return detectCallback(); + } + // Find the first symbol in the list that matches a tag + return async.detectSeries(symbols, (symbol, doneDetect) => { + ctags.findTags(tagsFile, symbol, (err, tags) => { + if (!tags) { + tags = []; + } + if (err) { + foundErr = err; + doneDetect(false); + } else if (tags.length) { + for (const tag of Array.from(tags)) { + tag.directory = projectPath; + } + foundTags = tags; + doneDetect(true); + } else { + doneDetect(false); + } + }); + }, detectCallback); + }, (err, foundTags) => { + callback(err, _.flatten(foundTags)); + }); + }, + + getAllTags(callback) { + const projectTags = []; + const task = Task.once(handlerPath, atom.project.getPaths(), () => callback(projectTags)); + task.on('tags', (tags) => { + projectTags.push(...tags); + }); + return task; + }, +}; diff --git a/packages/symbols-view/menus/symbols-view.cson b/packages/symbols-view/menus/symbols-view.cson new file mode 100644 index 000000000..9e1dc85b1 --- /dev/null +++ b/packages/symbols-view/menus/symbols-view.cson @@ -0,0 +1,17 @@ +'menu': [ + { + 'label': 'Packages' + 'submenu': [ + 'label': 'Symbols' + 'submenu': [ + { 'label': 'File Symbols', 'command': 'symbols-view:toggle-file-symbols' } + { 'label': 'Project Symbols', 'command': 'symbols-view:toggle-project-symbols' } + ] + ] + } +] + +'context-menu': + 'atom-text-editor:not([mini])': [ + { 'label': 'Go to Declaration', 'command': 'symbols-view:go-to-declaration' } + ] diff --git a/packages/symbols-view/package-lock.json b/packages/symbols-view/package-lock.json new file mode 100644 index 000000000..d72551850 --- /dev/null +++ b/packages/symbols-view/package-lock.json @@ -0,0 +1,1748 @@ +{ + "name": "symbols-view", + "version": "0.118.4", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "symbols-view", + "version": "0.118.4", + "license": "MIT", + "dependencies": { + "async": "^0.2.6", + "atom-select-list": "^0.7.0", + "ctags": "^3.1.0", + "fs-plus": "^3.0.0", + "fuzzaldrin": "^2.1.0", + "humanize-plus": "^1.8.2", + "temp": "^0.8.3", + "underscore-plus": "^1.6.6" + }, + "devDependencies": { + "babel-eslint": "^6.1.2", + "eslint": "^3.12.2", + "eslint-config-fbjs": "^1.1.1", + "eslint-plugin-babel": "^3.3.0", + "eslint-plugin-flowtype": "^2.29.1", + "eslint-plugin-jasmine": "^2.2.0", + "eslint-plugin-prefer-object-spread": "^1.1.0", + "eslint-plugin-react": "^5.2.2" + }, + "engines": { + "atom": "*" + } + }, + "node_modules/acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "dependencies": { + "acorn": "^3.0.4" + } + }, + "node_modules/acorn-jsx/node_modules/acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "dependencies": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "node_modules/ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true, + "peerDependencies": { + "ajv": ">=4.10.0" + } + }, + "node_modules/ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + }, + "node_modules/atom-select-list": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/atom-select-list/-/atom-select-list-0.7.2.tgz", + "integrity": "sha512-a707OB1DhLGjzqtFrtMQKH7BBxFuCh8UBoUWxgFOrLrSwVh3g+/TlVPVDOz12+U0mDu3mIrnYLqQyhywQOTxhw==", + "dependencies": { + "etch": "^0.12.6", + "fuzzaldrin": "^2.1.0" + } + }, + "node_modules/babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "node_modules/babel-eslint": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-6.1.2.tgz", + "integrity": "sha1-UpNBn+NnLWZZjTJ9qWlFZ7pqXy8=", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "dev": true, + "dependencies": { + "babel-traverse": "^6.0.20", + "babel-types": "^6.0.19", + "babylon": "^6.0.18", + "lodash.assign": "^4.0.0", + "lodash.pickby": "^4.0.0" + } + }, + "node_modules/babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "dependencies": { + "babel-runtime": "^6.22.0" + } + }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "node_modules/babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "dependencies": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "node_modules/babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "dependencies": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "node_modules/babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true, + "bin": { + "babylon": "bin/babylon.js" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "dependencies": { + "callsites": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "deprecated": "CircularJSON is in maintenance only, flatted is its successor.", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "dependencies": { + "restore-cursor": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/core-js": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", + "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/ctags": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ctags/-/ctags-3.1.0.tgz", + "integrity": "sha512-7/aiGLj8Ih7Ko3bAAg8bQUwHjOGXKQ7XC+bv+vLh84BtkVodPEOpOnr65FnWjX2oFWoKSaDuxe7jFHudD2Q0uw==", + "hasInstallScript": true, + "dependencies": { + "event-stream": "~3.1.0", + "nan": "^2.14.0" + } + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" + }, + "node_modules/es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dev": true, + "dependencies": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "node_modules/es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + } + }, + "node_modules/es6-set/node_modules/es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "dependencies": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "dev": true, + "dependencies": { + "babel-code-frame": "^6.16.0", + "chalk": "^1.1.3", + "concat-stream": "^1.5.2", + "debug": "^2.1.1", + "doctrine": "^2.0.0", + "escope": "^3.6.0", + "espree": "^3.4.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "glob": "^7.0.3", + "globals": "^9.14.0", + "ignore": "^3.2.0", + "imurmurhash": "^0.1.4", + "inquirer": "^0.12.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.5.1", + "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", + "lodash": "^4.0.0", + "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.1", + "pluralize": "^1.2.1", + "progress": "^1.1.8", + "require-uncached": "^1.0.2", + "shelljs": "^0.7.5", + "strip-bom": "^3.0.0", + "strip-json-comments": "~2.0.1", + "table": "^3.7.8", + "text-table": "~0.2.0", + "user-home": "^2.0.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-fbjs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-fbjs/-/eslint-config-fbjs-1.1.1.tgz", + "integrity": "sha1-3Sn42RLop1Ulfp7u8AuuHM5X9zo=", + "dev": true, + "peerDependencies": { + "babel-eslint": "^6.1.2", + "eslint": "^3.0.0", + "eslint-plugin-babel": "^3.3.0", + "eslint-plugin-flowtype": "^2.15.0", + "eslint-plugin-react": "^5.2.2" + } + }, + "node_modules/eslint-plugin-babel": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-3.3.0.tgz", + "integrity": "sha1-L0lK7c9vSqTnW5FVmAg3vB+94ZM=", + "dev": true, + "peerDependencies": { + "eslint": ">=1.0.0" + } + }, + "node_modules/eslint-plugin-flowtype": { + "version": "2.50.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.3.tgz", + "integrity": "sha512-X+AoKVOr7Re0ko/yEXyM5SSZ0tazc6ffdIOocp2fFUlWoDt7DV0Bz99mngOkAFLOAWjqRA5jPwqUCbrx13XoxQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.10" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": ">=2.0.0" + } + }, + "node_modules/eslint-plugin-jasmine": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.10.1.tgz", + "integrity": "sha1-VzO3CedR9LxA4x4cFpib0s377Jc=", + "dev": true, + "engines": { + "node": ">=4", + "npm": ">=2" + } + }, + "node_modules/eslint-plugin-prefer-object-spread": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-object-spread/-/eslint-plugin-prefer-object-spread-1.2.1.tgz", + "integrity": "sha1-J/uRhTaQzOs65hAdnIrsxqZ6QCw=", + "dev": true, + "engines": { + "node": ">=4.0.0" + }, + "peerDependencies": { + "eslint": ">=0.8.0" + } + }, + "node_modules/eslint-plugin-react": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-5.2.2.tgz", + "integrity": "sha1-fbBo4fVIf2hx5N7vNqOBwwPqwWE=", + "dev": true, + "dependencies": { + "doctrine": "^1.2.2", + "jsx-ast-utils": "^1.2.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "dependencies": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "dependencies": { + "estraverse": "^4.0.0" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "dependencies": { + "estraverse": "^4.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etch": { + "version": "0.12.8", + "resolved": "https://registry.npmjs.org/etch/-/etch-0.12.8.tgz", + "integrity": "sha512-dFLRe4wLroVtwzyy1vGlE3BSDZHiL0kZME5XgNGzZIULcYTvVno8vbiIleAesoKJmwWaxDTzG+4eppg2zk14JQ==" + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/event-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.1.7.tgz", + "integrity": "sha1-tMVAAS0P4UmEIPPYlGAI22OTw3o=", + "dependencies": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.2", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "node_modules/exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "dependencies": { + "type": "^2.0.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "dependencies": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "dependencies": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + }, + "node_modules/fs-plus": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz", + "integrity": "sha512-Se2PJdOWXqos1qVTkvqqjb0CSnfBnwwD+pq+z4ksT+e97mEShod/hrNg0TRCCsXPbJzcIq+NuzQhigunMWMJUA==", + "dependencies": { + "async": "^1.5.2", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2", + "underscore-plus": "1.x" + } + }, + "node_modules/fs-plus/node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fuzzaldrin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz", + "integrity": "sha1-kCBMPi/appQbso0WZF1BgGOpDps=" + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dev": true, + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "dependencies": { + "is-property": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/humanize-plus": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/humanize-plus/-/humanize-plus-1.8.2.tgz", + "integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "dev": true, + "dependencies": { + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "node_modules/interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "dev": true + }, + "node_modules/is-my-json-valid": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz", + "integrity": "sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==", + "dev": true, + "dependencies": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "node_modules/is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "dependencies": { + "jsonify": "~0.0.0" + } + }, + "node_modules/jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "node_modules/lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=" + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "node_modules/mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dependencies": { + "minimist": "0.0.8" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true + }, + "node_modules/nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "dependencies": { + "through": "~2.3" + } + }, + "node_modules/pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "mute-stream": "0.0.5" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "node_modules/require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "dependencies": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", + "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "dependencies": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true, + "dependencies": { + "once": "^1.3.0" + } + }, + "node_modules/rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "iojs": "*", + "node": ">=0.11.0" + } + }, + "node_modules/slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/split/-/split-0.2.10.tgz", + "integrity": "sha1-Zwl8YB1pfOE2j0GPBs0gHPBSGlc=", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dependencies": { + "duplexer": "~0.1.1" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "dependencies": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "dependencies": { + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "node_modules/to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "node_modules/underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" + }, + "node_modules/underscore-plus": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.7.0.tgz", + "integrity": "sha512-A3BEzkeicFLnr+U/Q3EyWwJAQPbA19mtZZ4h+lLq3ttm9kn8WC4R3YpuJZEXmWdLjYP47Zc8aLZm9kwdv+zzvA==", + "dependencies": { + "underscore": "^1.9.1" + } + }, + "node_modules/user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/packages/symbols-view/package.json b/packages/symbols-view/package.json new file mode 100644 index 000000000..93366633f --- /dev/null +++ b/packages/symbols-view/package.json @@ -0,0 +1,53 @@ +{ + "name": "symbols-view", + "version": "0.118.4", + "main": "./lib/main", + "description": "Jump to a function/method in the current editor with `cmd-r`.", + "license": "MIT", + "activationCommands": { + "atom-workspace": [ + "symbols-view:toggle-project-symbols" + ], + "atom-text-editor": [ + "symbols-view:go-to-declaration", + "symbols-view:return-from-declaration", + "symbols-view:toggle-file-symbols" + ] + }, + "dependencies": { + "async": "^0.2.6", + "atom-select-list": "^0.7.0", + "ctags": "^3.1.0", + "fs-plus": "^3.0.0", + "fuzzaldrin": "^2.1.0", + "humanize-plus": "^1.8.2", + "temp": "^0.8.3", + "underscore-plus": "^1.6.6" + }, + "configSchema": { + "useEditorGrammarAsCtagsLanguage": { + "default": true, + "type": "boolean", + "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." + }, + "quickJumpToFileSymbol": { + "default": true, + "type": "boolean", + "description": "Automatically visit selected file-symbols" + } + }, + "repository": "https://github.com/pulsar-edit/symbols-view", + "engines": { + "atom": "*" + }, + "devDependencies": { + "babel-eslint": "^6.1.2", + "eslint": "^3.12.2", + "eslint-config-fbjs": "^1.1.1", + "eslint-plugin-babel": "^3.3.0", + "eslint-plugin-flowtype": "^2.29.1", + "eslint-plugin-jasmine": "^2.2.0", + "eslint-plugin-prefer-object-spread": "^1.1.0", + "eslint-plugin-react": "^5.2.2" + } +} diff --git a/packages/symbols-view/spec/async-spec-helpers.js b/packages/symbols-view/spec/async-spec-helpers.js new file mode 100644 index 000000000..7642fdfb9 --- /dev/null +++ b/packages/symbols-view/spec/async-spec-helpers.js @@ -0,0 +1,67 @@ +/** @babel */ + +export function beforeEach(fn) { + global.beforeEach(function() { + const result = fn(); + if (result instanceof Promise) { + waitsForPromise(() => result); + } + }); +} + +export function afterEach(fn) { + global.afterEach(function() { + const result = fn(); + if (result instanceof Promise) { + waitsForPromise(() => result); + } + }); +} + +['it', 'fit', 'ffit', 'fffit'].forEach(function(name) { + module.exports[name] = function(description, fn) { + global[name](description, function() { + const result = fn(); + if (result instanceof Promise) { + waitsForPromise(() => result); + } + }); + }; +}); + +export async function conditionPromise(condition) { + const startTime = Date.now(); + + while (true) { + await timeoutPromise(100); + + let conditionResult = condition(); + if (condition instanceof Promise) { + conditionResult = await conditionResult; + } + + if (conditionResult) { + return; + } + + if (Date.now() - startTime > 5000) { + throw new Error('Timed out waiting on condition'); + } + } +} + +export function timeoutPromise(timeout) { + return new Promise(function(resolve) { + global.setTimeout(resolve, timeout); + }); +} + +function waitsForPromise(fn) { + const promise = fn(); + global.waitsFor('spec promise to resolve', function(done) { + promise.then(done, function(error) { + jasmine.getEnv().currentSpec.fail(error); + done(); + }); + }); +} diff --git a/packages/symbols-view/spec/fixtures/c/sample.c b/packages/symbols-view/spec/fixtures/c/sample.c new file mode 100644 index 000000000..5a98bf4c1 --- /dev/null +++ b/packages/symbols-view/spec/fixtures/c/sample.c @@ -0,0 +1,6 @@ +#define UNUSED(x) (void)(x) + +static void f(int x) +{ + UNUSED(x); +} diff --git a/packages/symbols-view/spec/fixtures/js/sample.js b/packages/symbols-view/spec/fixtures/js/sample.js new file mode 100644 index 000000000..fb33b0b43 --- /dev/null +++ b/packages/symbols-view/spec/fixtures/js/sample.js @@ -0,0 +1,13 @@ +var quicksort = function () { + var sort = function(items) { + if (items.length <= 1) return items; + var pivot = items.shift(), current, left = [], right = []; + while(items.length > 0) { + current = items.shift(); + current < pivot ? left.push(current) : right.push(current); + } + return sort(left).concat(pivot).concat(sort(right)); + }; + + return sort(Array.apply(this, arguments)); +}; \ No newline at end of file diff --git a/packages/symbols-view/spec/fixtures/js/tagged-duplicate.js b/packages/symbols-view/spec/fixtures/js/tagged-duplicate.js new file mode 100644 index 000000000..a4b6fbb8a --- /dev/null +++ b/packages/symbols-view/spec/fixtures/js/tagged-duplicate.js @@ -0,0 +1,3 @@ + function duplicate() { + return false; + } diff --git a/packages/symbols-view/spec/fixtures/js/tagged.js b/packages/symbols-view/spec/fixtures/js/tagged.js new file mode 100644 index 000000000..4adaac609 --- /dev/null +++ b/packages/symbols-view/spec/fixtures/js/tagged.js @@ -0,0 +1,11 @@ +var thisIsCrazy = true; + +function callMeMaybe() { + return "here's my number"; +} + +var iJustMetYou = callMeMaybe(); + +function duplicate() { + return true; +} diff --git a/packages/symbols-view/spec/fixtures/ruby/file1.rb b/packages/symbols-view/spec/fixtures/ruby/file1.rb new file mode 100644 index 000000000..62697a7b3 --- /dev/null +++ b/packages/symbols-view/spec/fixtures/ruby/file1.rb @@ -0,0 +1,33 @@ +module A::Foo + B = 'b' + + def bar! + + end + + def bar? + + end + + def baz + end + + def baz=(*) + end +end + +if bar? + baz + bar! +elsif !bar! + baz= 1 + baz = 2 + Foo = 3 + { :baz => 4 } + A::Foo::B + C::Foo::B + D::Foo::E +end + +module D::Foo +end diff --git a/packages/symbols-view/spec/symbols-view-spec.js b/packages/symbols-view/spec/symbols-view-spec.js new file mode 100644 index 000000000..97cebe8d3 --- /dev/null +++ b/packages/symbols-view/spec/symbols-view-spec.js @@ -0,0 +1,532 @@ +/** @babel */ +/* eslint-env jasmine */ + +import path from 'path'; +import etch from 'etch'; +import fs from 'fs-plus'; +import temp from 'temp'; +import SymbolsView from '../lib/symbols-view'; +import TagGenerator from '../lib/tag-generator'; + +import {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise} from './async-spec-helpers'; + +describe('SymbolsView', () => { + let [symbolsView, activationPromise, editor, directory] = []; + + const getWorkspaceView = () => atom.views.getView(atom.workspace); + const getEditorView = () => atom.views.getView(atom.workspace.getActiveTextEditor()); + + beforeEach(async () => { + jasmine.unspy(global, 'setTimeout'); + + atom.project.setPaths([ + temp.mkdirSync('other-dir-'), + temp.mkdirSync('atom-symbols-view-'), + ]); + + directory = atom.project.getDirectories()[1]; + fs.copySync(path.join(__dirname, 'fixtures', 'js'), atom.project.getPaths()[1]); + + activationPromise = atom.packages.activatePackage('symbols-view'); + jasmine.attachToDOM(getWorkspaceView()); + }); + + describe('when tags can be generated for a file', () => { + beforeEach(async () => { + await atom.workspace.open(directory.resolve('sample.js')); + }); + + it('initially displays all JavaScript functions with line numbers', async () => { + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + expect(symbolsView.selectListView.refs.loadingMessage).toBeUndefined(); + expect(document.body.contains(symbolsView.element)).toBe(true); + expect(symbolsView.element.querySelectorAll('li').length).toBe(2); + expect(symbolsView.element.querySelector('li:first-child .primary-line')).toHaveText('quicksort'); + expect(symbolsView.element.querySelector('li:first-child .secondary-line')).toHaveText('Line 1'); + expect(symbolsView.element.querySelector('li:last-child .primary-line')).toHaveText('quicksort.sort'); + expect(symbolsView.element.querySelector('li:last-child .secondary-line')).toHaveText('Line 2'); + expect(symbolsView.selectListView.refs.errorMessage).toBeUndefined(); + }); + + it('caches tags until the editor changes', async () => { + editor = atom.workspace.getActiveTextEditor(); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + await symbolsView.cancel(); + + spyOn(symbolsView, 'generateTags').andCallThrough(); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + expect(symbolsView.selectListView.refs.loadingMessage).toBeUndefined(); + expect(symbolsView.element.querySelectorAll('li').length).toBe(2); + expect(symbolsView.generateTags).not.toHaveBeenCalled(); + await symbolsView.cancel(); + + await editor.save(); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + expect(symbolsView.selectListView.refs.loadingMessage).toBeUndefined(); + expect(symbolsView.element.querySelectorAll('li').length).toBe(2); + expect(symbolsView.generateTags).toHaveBeenCalled(); + editor.destroy(); + expect(symbolsView.cachedTags).toEqual({}); + }); + + it('displays an error when no tags match text in mini-editor', async () => { + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + + symbolsView.selectListView.refs.queryEditor.setText('nothing will match this'); + await conditionPromise(() => symbolsView.selectListView.refs.emptyMessage); + expect(document.body.contains(symbolsView.element)).toBe(true); + expect(symbolsView.element.querySelectorAll('li').length).toBe(0); + expect(symbolsView.selectListView.refs.emptyMessage.textContent.length).toBeGreaterThan(0); + + // Should remove error + symbolsView.selectListView.refs.queryEditor.setText(''); + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + expect(symbolsView.element.querySelectorAll('li').length).toBe(2); + expect(symbolsView.selectListView.refs.emptyMessage).toBeUndefined(); + }); + + it('moves the cursor to the selected function', async () => { + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + + symbolsView.element.querySelectorAll('li')[1].click(); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 2]); + }); + }); + + describe("when tags can't be generated for a file", () => { + beforeEach(async () => { + await atom.workspace.open('sample.txt'); + }); + + it('shows an error message when no matching tags are found', async () => { + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + + await conditionPromise(() => symbolsView.selectListView.refs.emptyMessage); + expect(document.body.contains(symbolsView.element)); + expect(symbolsView.element.querySelectorAll('li').length).toBe(0); + expect(symbolsView.selectListView.refs.emptyMessage).toBeVisible(); + expect(symbolsView.selectListView.refs.emptyMessage.textContent.length).toBeGreaterThan(0); + expect(symbolsView.selectListView.refs.loadingMessage).not.toBeVisible(); + }); + }); + + describe('TagGenerator', () => { + it('generates tags for all JavaScript functions', async () => { + let tags = []; + const sampleJsPath = directory.resolve('sample.js'); + await new TagGenerator(sampleJsPath).generate().then(o => tags = o); + expect(tags.length).toBe(2); + expect(tags[0].name).toBe('quicksort'); + expect(tags[0].position.row).toBe(0); + expect(tags[1].name).toBe('quicksort.sort'); + expect(tags[1].position.row).toBe(1); + }); + + it('generates no tags for text file', async () => { + let tags = []; + const sampleJsPath = directory.resolve('sample.txt'); + await new TagGenerator(sampleJsPath).generate().then(o => tags = o); + expect(tags.length).toBe(0); + }); + }); + + describe('go to declaration', () => { + it("doesn't move the cursor when no declaration is found", async () => { + await atom.workspace.open(directory.resolve('tagged.js')); + editor = atom.workspace.getActiveTextEditor(); + editor.setCursorBufferPosition([0, 2]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await activationPromise; + + expect(editor.getCursorBufferPosition()).toEqual([0, 2]); + }); + + it('moves the cursor to the declaration when there is a single matching declaration', async () => { + await atom.workspace.open(directory.resolve('tagged.js')); + editor = atom.workspace.getActiveTextEditor(); + editor.setCursorBufferPosition([6, 24]); + spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(editor.getCursorBufferPosition()).toEqual([2, 0]); + }); + + it('correctly moves the cursor to the declaration of a C preprocessor macro', async () => { + atom.project.setPaths([temp.mkdirSync('atom-symbols-view-c-')]); + fs.copySync(path.join(__dirname, 'fixtures', 'c'), atom.project.getPaths()[0]); + + await atom.packages.activatePackage('language-c'); + await atom.workspace.open('sample.c'); + + editor = atom.workspace.getActiveTextEditor(); + editor.setCursorBufferPosition([4, 4]); + spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(editor.getCursorBufferPosition()).toEqual([0, 0]); + }); + + it('displays matches when more than one exists and opens the selected match', async () => { + await atom.workspace.open(directory.resolve('tagged.js')); + editor = atom.workspace.getActiveTextEditor(); + editor.setCursorBufferPosition([8, 14]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + symbolsView = atom.workspace.getModalPanels()[0].item; + + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + expect(symbolsView.element.querySelectorAll('li').length).toBe(2); + expect(symbolsView.element).toBeVisible(); + spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); + symbolsView.selectListView.confirmSelection(); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getPath()).toBe(directory.resolve('tagged-duplicate.js')); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 4]); + }); + + it('includes ? and ! characters in ruby symbols', async () => { + atom.project.setPaths([temp.mkdirSync('atom-symbols-view-ruby-')]); + fs.copySync(path.join(__dirname, 'fixtures', 'ruby'), atom.project.getPaths()[0]); + + await atom.packages.activatePackage('language-ruby'); + await atom.workspace.open('file1.rb'); + + spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([18, 4]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await activationPromise; + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([7, 2]); + SymbolsView.prototype.moveToPosition.reset(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([19, 2]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([11, 2]); + SymbolsView.prototype.moveToPosition.reset(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([20, 5]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([3, 2]); + SymbolsView.prototype.moveToPosition.reset(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([21, 7]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([3, 2]); + }); + + it('handles jumping to assignment ruby method definitions', async () => { + atom.project.setPaths([temp.mkdirSync('atom-symbols-view-ruby-')]); + fs.copySync(path.join(__dirname, 'fixtures', 'ruby'), atom.project.getPaths()[0]); + + await atom.packages.activatePackage('language-ruby'); + await atom.workspace.open('file1.rb'); + spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([22, 5]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([14, 2]); + SymbolsView.prototype.moveToPosition.reset(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([23, 5]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([14, 2]); + SymbolsView.prototype.moveToPosition.reset(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([24, 5]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); + SymbolsView.prototype.moveToPosition.reset(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([25, 5]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([11, 2]); + }); + + it('handles jumping to fully qualified ruby constant definitions', async () => { + atom.project.setPaths([temp.mkdirSync('atom-symbols-view-ruby-')]); + fs.copySync(path.join(__dirname, 'fixtures', 'ruby'), atom.project.getPaths()[0]); + await atom.packages.activatePackage('language-ruby'); + await atom.workspace.open('file1.rb'); + spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([26, 10]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 2]); + SymbolsView.prototype.moveToPosition.reset(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([27, 5]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); + SymbolsView.prototype.moveToPosition.reset(); + atom.workspace.getActiveTextEditor().setCursorBufferPosition([28, 5]); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([31, 0]); + }); + + describe('return from declaration', () => { + it("doesn't do anything when no go-to have been triggered", async () => { + await atom.workspace.open(directory.resolve('tagged.js')); + editor = atom.workspace.getActiveTextEditor(); + editor.setCursorBufferPosition([6, 0]); + atom.commands.dispatch(getEditorView(), 'symbols-view:return-from-declaration'); + + await activationPromise; + expect(editor.getCursorBufferPosition()).toEqual([6, 0]); + }); + + it('returns to previous row and column', async () => { + await atom.workspace.open(directory.resolve('tagged.js')); + editor = atom.workspace.getActiveTextEditor(); + editor.setCursorBufferPosition([6, 24]); + spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await activationPromise; + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(editor.getCursorBufferPosition()).toEqual([2, 0]); + atom.commands.dispatch(getEditorView(), 'symbols-view:return-from-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 2); + expect(editor.getCursorBufferPosition()).toEqual([6, 24]); + }); + }); + + describe("when the tag is in a file that doesn't exist", () => { + it("doesn't display the tag", async () => { + fs.removeSync(directory.resolve('tagged-duplicate.js')); + await atom.workspace.open(directory.resolve('tagged.js')); + + editor = atom.workspace.getActiveTextEditor(); + editor.setCursorBufferPosition([8, 14]); + spyOn(SymbolsView.prototype, 'moveToPosition').andCallThrough(); + atom.commands.dispatch(getEditorView(), 'symbols-view:go-to-declaration'); + + await conditionPromise(() => SymbolsView.prototype.moveToPosition.callCount === 1); + expect(editor.getCursorBufferPosition()).toEqual([8, 0]); + }); + }); + }); + + describe('project symbols', () => { + it('displays all tags', async () => { + await atom.workspace.open(directory.resolve('tagged.js')); + expect(getWorkspaceView().querySelector('.symbols-view')).toBeNull(); + atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); + + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + const directoryBasename = path.basename(directory.getPath()); + const taggedFile = path.join(directoryBasename, 'tagged.js'); + expect(symbolsView.selectListView.refs.loadingMessage).toBeUndefined(); + expect(document.body.contains(symbolsView.element)).toBe(true); + expect(symbolsView.element.querySelectorAll('li').length).toBe(4); + expect(symbolsView.element.querySelector('li:first-child .primary-line')).toHaveText('callMeMaybe'); + expect(symbolsView.element.querySelector('li:first-child .secondary-line')).toHaveText(taggedFile); + expect(symbolsView.element.querySelector('li:last-child .primary-line')).toHaveText('thisIsCrazy'); + expect(symbolsView.element.querySelector('li:last-child .secondary-line')).toHaveText(taggedFile); + atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); + fs.removeSync(directory.resolve('tags')); + + await conditionPromise(() => symbolsView.reloadTags); + atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); + + await conditionPromise(() => symbolsView.selectListView.refs.loadingMessage); + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length === 0); + }); + + describe('when there is only one project', () => { + beforeEach(async () => atom.project.setPaths([directory.getPath()])); + + it("does not include the root directory's name when displaying the tag's filename", async () => { + await atom.workspace.open(directory.resolve('tagged.js')); + expect(getWorkspaceView().querySelector('.symbols-view')).toBeNull(); + atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); + + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + expect(symbolsView.element.querySelector('li:first-child .primary-line')).toHaveText('callMeMaybe'); + expect(symbolsView.element.querySelector('li:first-child .secondary-line')).toHaveText('tagged.js'); + }); + }); + + describe('when selecting a tag', () => { + describe("when the file doesn't exist", () => { + beforeEach(async () => fs.removeSync(directory.resolve('tagged.js'))); + + it("doesn't open the editor", async () => { + atom.commands.dispatch(getWorkspaceView(), 'symbols-view:toggle-project-symbols'); + + await activationPromise; + + symbolsView = atom.workspace.getModalPanels()[0].item; + + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + spyOn(atom.workspace, 'open').andCallThrough(); + symbolsView.element.querySelector('li:first-child').click(); + await conditionPromise(() => symbolsView.selectListView.refs.errorMessage); + expect(atom.workspace.open).not.toHaveBeenCalled(); + expect(symbolsView.selectListView.refs.errorMessage.textContent.length).toBeGreaterThan(0); + }); + }); + }); + }); + + describe('when useEditorGrammarAsCtagsLanguage is set to true', () => { + it("uses the language associated with the editor's grammar", async () => { + atom.config.set('symbols-view.useEditorGrammarAsCtagsLanguage', true); + + await atom.packages.activatePackage('language-javascript'); + await atom.workspace.open('sample.javascript'); + atom.workspace.getActiveTextEditor().setText('var test = function() {}'); + await atom.workspace.getActiveTextEditor().save(); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await activationPromise; + + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.selectListView.refs.emptyMessage); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + + atom.workspace.getActiveTextEditor().setGrammar(atom.grammars.grammarForScopeName('source.js')); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length === 1); + expect(document.body.contains(symbolsView.element)).toBe(true); + expect(symbolsView.element.querySelector('li:first-child .primary-line')).toHaveText('test'); + expect(symbolsView.element.querySelector('li:first-child .secondary-line')).toHaveText('Line 1'); + }); + }); + + describe('match highlighting', () => { + beforeEach(async () => { + await atom.workspace.open(directory.resolve('sample.js')); + }); + + it('highlights an exact match', async () => { + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + symbolsView.selectListView.refs.queryEditor.setText('quicksort'); + await getOrScheduleUpdatePromise(); + const resultView = symbolsView.element.querySelector('.selected'); + const matches = resultView.querySelectorAll('.character-match'); + expect(matches.length).toBe(1); + expect(matches[0].textContent).toBe('quicksort'); + }); + + it('highlights a partial match', async () => { + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + symbolsView.selectListView.refs.queryEditor.setText('quick'); + await getOrScheduleUpdatePromise(); + const resultView = symbolsView.element.querySelector('.selected'); + const matches = resultView.querySelectorAll('.character-match'); + expect(matches.length).toBe(1); + expect(matches[0].textContent).toBe('quick'); + }); + + it('highlights multiple matches in the symbol name', async () => { + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + symbolsView.selectListView.refs.queryEditor.setText('quicort'); + await getOrScheduleUpdatePromise(); + const resultView = symbolsView.element.querySelector('.selected'); + const matches = resultView.querySelectorAll('.character-match'); + expect(matches.length).toBe(2); + expect(matches[0].textContent).toBe('quic'); + expect(matches[1].textContent).toBe('ort'); + }); + }); + + describe('quickjump to symbol', () => { + beforeEach(async () => { + await atom.workspace.open(directory.resolve('sample.js')); + }); + + it('jumps to the selected function', async () => { + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + symbolsView.selectListView.selectNext(); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 2]); + }); + + it('restores previous editor state on cancel', async () => { + const bufferRanges = [{start: {row: 0, column: 0}, end: {row: 0, column: 3}}]; + atom.workspace.getActiveTextEditor().setSelectedBufferRanges(bufferRanges); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + + symbolsView.selectListView.selectNext(); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([1, 2]); + await symbolsView.cancel(); + expect(atom.workspace.getActiveTextEditor().getSelectedBufferRanges()).toEqual(bufferRanges); + }); + }); + + describe('when quickJumpToSymbol is set to false', async () => { + beforeEach(async () => { + atom.config.set('symbols-view.quickJumpToFileSymbol', false); + await atom.workspace.open(directory.resolve('sample.js')); + }); + + it("won't jumps to the selected function", async () => { + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); + atom.commands.dispatch(getEditorView(), 'symbols-view:toggle-file-symbols'); + + await activationPromise; + symbolsView = atom.workspace.getModalPanels()[0].item; + await conditionPromise(() => symbolsView.element.querySelectorAll('li').length > 0); + symbolsView.selectListView.selectNext(); + expect(atom.workspace.getActiveTextEditor().getCursorBufferPosition()).toEqual([0, 0]); + }); + }); +}); + +function getOrScheduleUpdatePromise () { + return new Promise((resolve) => etch.getScheduler().updateDocument(resolve)) +} diff --git a/packages/symbols-view/styles/symbols-view.less b/packages/symbols-view/styles/symbols-view.less new file mode 100644 index 000000000..63262cb5d --- /dev/null +++ b/packages/symbols-view/styles/symbols-view.less @@ -0,0 +1,7 @@ +@import "ui-variables"; + +// Highlight matched text +.symbols-view .list-group .character-match { + color: @text-color-highlight; + font-weight: bold; +} diff --git a/packages/symbols-view/vendor/ctags-darwin b/packages/symbols-view/vendor/ctags-darwin new file mode 100755 index 000000000..86576c957 Binary files /dev/null and b/packages/symbols-view/vendor/ctags-darwin differ diff --git a/packages/symbols-view/vendor/ctags-linux b/packages/symbols-view/vendor/ctags-linux new file mode 100755 index 000000000..0e229e3ef Binary files /dev/null and b/packages/symbols-view/vendor/ctags-linux differ diff --git a/packages/symbols-view/vendor/ctags-win32.exe b/packages/symbols-view/vendor/ctags-win32.exe new file mode 100644 index 000000000..b688c2936 Binary files /dev/null and b/packages/symbols-view/vendor/ctags-win32.exe differ diff --git a/yarn.lock b/yarn.lock index baa4933c5..52a0388cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9087,9 +9087,8 @@ sylvester@^0.0.12: resolved "https://registry.yarnpkg.com/sylvester/-/sylvester-0.0.12.tgz#5a884415cd2d002c57e7a3aac99462a75ce9fdb4" integrity sha512-SzRP5LQ6Ts2G5NyAa/jg16s8e3R7rfdFjizy1zeoecYWw+nGL+YA1xZvW/+iJmidBGSdLkuvdwTYEyJEb+EiUw== -"symbols-view@https://codeload.github.com/atom/symbols-view/legacy.tar.gz/refs/tags/v0.118.4": +"symbols-view@file:./packages/symbols-view": version "0.118.4" - resolved "https://codeload.github.com/atom/symbols-view/legacy.tar.gz/refs/tags/v0.118.4#cd1b515d4a3d720402b85301ea8e4d6c8815aaf2" dependencies: async "^0.2.6" atom-select-list "^0.7.0"