Bundled symbols-view

This commit is contained in:
Maurício Szabo 2023-04-17 23:36:38 -03:00
parent 763e41e48e
commit 6e78ee9c47
38 changed files with 3788 additions and 4 deletions

View File

@ -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",

View File

@ -0,0 +1 @@
**/fixtures/**/*.js

View File

@ -0,0 +1,7 @@
module.exports = {
parser: 'babel-eslint',
extends: 'fbjs',
globals: {
atom: true
}
};

View File

@ -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.

1
packages/symbols-view/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
[See how you can contribute](https://github.com/pulsar-edit/.github/blob/main/CONTRIBUTING.md)

View File

@ -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.

View File

@ -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|<kbd>ctrl-r</kbd>|<kbd>cmd-r</kbd>|<kbd>ctrl-r</kbd>|
|`symbols-view:toggle-project-symbols`|Show all symbols in the project|<kbd>ctrl-shift-r</kbd>|<kbd>cmd-shift-r</kbd>|<kbd>ctrl-shift-r</kbd>|
|`symbols-view:go-to-declaration`|Jump to the symbol under the cursor|<kbd>ctrl-alt-down</kbd>|<kbd>cmd-alt-down</kbd>||
|`symbols-view:return-from-declaration`|Return from the jump|<kbd>ctrl-alt-up</kbd>|<kbd>cmd-alt-up</kbd>||
This package uses [ctags](http://ctags.sourceforge.net).
![](https://f.cloud.github.com/assets/671378/2241860/30ef0b2e-9ce8-11e3-86e2-2c17c0885fa4.png)

View File

@ -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

View File

@ -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'

View File

@ -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/

View File

@ -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];
}
}

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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();
}
});
}
}

View File

@ -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()
);
}

View File

@ -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;
},
};

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
},
});
});
}
}

View File

@ -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;
},
};

View File

@ -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' }
]

1748
packages/symbols-view/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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"
}
}

View File

@ -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();
});
});
}

View File

@ -0,0 +1,6 @@
#define UNUSED(x) (void)(x)
static void f(int x)
{
UNUSED(x);
}

View File

@ -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));
};

View File

@ -0,0 +1,3 @@
function duplicate() {
return false;
}

View File

@ -0,0 +1,11 @@
var thisIsCrazy = true;
function callMeMaybe() {
return "here's my number";
}
var iJustMetYou = callMeMaybe();
function duplicate() {
return true;
}

View File

@ -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

View File

@ -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))
}

View File

@ -0,0 +1,7 @@
@import "ui-variables";
// Highlight matched text
.symbols-view .list-group .character-match {
color: @text-color-highlight;
font-weight: bold;
}

BIN
packages/symbols-view/vendor/ctags-darwin vendored Executable file

Binary file not shown.

BIN
packages/symbols-view/vendor/ctags-linux vendored Executable file

Binary file not shown.

Binary file not shown.

View File

@ -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"