10 |
11 | Permission is hereby granted, free of charge, to any person obtaining a copy of
12 | this software and associated documentation files (the "Software"), to deal in
13 | the Software without restriction, including without limitation the rights to
14 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
15 | the Software, and to permit persons to whom the Software is furnished to do so,
16 | subject to the following conditions:
17 |
18 | The above copyright notice and this permission notice shall be included in all
19 | copies or substantial portions of the Software.
20 |
21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
23 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
24 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # php-integrator/atom-tooltips-legacy-php56
2 | ## Legacy
3 | This is a legacy version that requires PHP >= 5.6. Users that are on PHP 7.1 can and should use [the newer version](https://github.com/php-integrator/atom-base).
4 |
5 | This package only exists to cater towards users that are not in any position to upgrade their host PHP version. As a result, any issues that appear in this package will not be fixed, no new features will be added and no enhancements will be done.
6 |
7 | ## About
8 | This package provides tooltips for your PHP source code using [PHP Integrator](https://github.com/php-integrator/atom-base).
9 |
10 | **Note that the [php-integrator-base](https://github.com/php-integrator/atom-base) package is required and needs to be set up correctly for this package to function correctly.**
11 |
12 | What is included?
13 | * Tooltips showing for global constants and functions.
14 | * Tooltips showing documentation for class, interface and trait names.
15 | * Tooltips showing documentation for class, interface and trait members.
16 | * Tooltips showing documentation for use statements (if the referenced item is an actual structure).
17 |
18 | 
19 |
--------------------------------------------------------------------------------
/lib/AbstractProvider.coffee:
--------------------------------------------------------------------------------
1 | $ = require 'jquery'
2 | SubAtom = require 'sub-atom'
3 |
4 | module.exports =
5 |
6 | ##*
7 | # Base class for providers.
8 | ##
9 | class AbstractProvider
10 | ###*
11 | * The class selectors for which a hover event will be triggered.
12 | ###
13 | hoverEventSelectors: ''
14 |
15 | ###*
16 | * The service (that can be used to query the source code and contains utility methods).
17 | ###
18 | service: null
19 |
20 | ###*
21 | * Keeps track of the currently pending promise.
22 | ###
23 | pendingPromise: null
24 |
25 | ###*
26 | * Initializes this provider.
27 | *
28 | * @param {mixed} service
29 | ###
30 | activate: (@service) ->
31 | dependentPackage = 'language-php'
32 |
33 | # It could be that the dependent package is already active, in that case we can continue immediately. If not,
34 | # we'll need to wait for the listener to be invoked
35 | if atom.packages.isPackageActive(dependentPackage)
36 | @doActualInitialization()
37 |
38 | atom.packages.onDidActivatePackage (packageData) =>
39 | return if packageData.name != dependentPackage
40 |
41 | @doActualInitialization()
42 |
43 | atom.packages.onDidDeactivatePackage (packageData) =>
44 | return if packageData.name != dependentPackage
45 |
46 | @deactivate()
47 |
48 | ###*
49 | * Does the actual initialization.
50 | ###
51 | doActualInitialization: () ->
52 | atom.workspace.observeTextEditors (editor) =>
53 | if /text.html.php$/.test(editor.getGrammar().scopeName)
54 | @registerEvents(editor)
55 |
56 | # When you go back to only have one pane the events are lost, so need to re-register.
57 | atom.workspace.onDidDestroyPane (pane) =>
58 | panes = atom.workspace.getPanes()
59 |
60 | if panes.length == 1
61 | @registerEventsForPane(panes[0])
62 |
63 | # Having to re-register events as when a new pane is created the old panes lose the events.
64 | atom.workspace.onDidAddPane (observedPane) =>
65 | panes = atom.workspace.getPanes()
66 |
67 | for pane in panes
68 | if pane != observedPane
69 | @registerEventsForPane(pane)
70 |
71 | atom.workspace.onDidStopChangingActivePaneItem (item) =>
72 | @removePopover()
73 |
74 | ###*
75 | * Registers the necessary event handlers for the editors in the specified pane.
76 | *
77 | * @param {Pane} pane
78 | ###
79 | registerEventsForPane: (pane) ->
80 | for paneItem in pane.items
81 | if atom.workspace.isTextEditor(paneItem)
82 | if /text.html.php$/.test(paneItem.getGrammar().scopeName)
83 | @registerEvents(paneItem)
84 |
85 | ###*
86 | * Deactives the provider.
87 | ###
88 | deactivate: () ->
89 | if @subAtom
90 | @subAtom.dispose()
91 | @subAtom = null
92 |
93 | @removePopover()
94 |
95 | ###*
96 | * Registers the necessary event handlers.
97 | *
98 | * @param {TextEditor} editor TextEditor to register events to.
99 | ###
100 | registerEvents: (editor) ->
101 | textEditorElement = atom.views.getView(editor)
102 | scrollViewElement = textEditorElement.querySelector('.scroll-view')
103 |
104 | if scrollViewElement?
105 | @getSubAtom().add scrollViewElement, 'mouseover', @hoverEventSelectors, (event) =>
106 | selector = @getSelectorFromEvent(event)
107 |
108 | if selector == null
109 | return
110 |
111 | editorViewComponent = atom.views.getView(editor).component
112 |
113 | # Ticket #140 - In rare cases the component is null.
114 | if editorViewComponent
115 | cursorPosition = editorViewComponent.screenPositionForMouseEvent(event)
116 |
117 | @removePopover()
118 | @showPopoverFor(editor, selector, cursorPosition)
119 |
120 | @getSubAtom().add scrollViewElement, 'mouseout', @hoverEventSelectors, (event) =>
121 | @removePopover()
122 |
123 | horizontalScrollbar = textEditorElement.querySelector('.horizontal-scrollbar')
124 |
125 | if horizontalScrollbar?
126 | @getSubAtom().add horizontalScrollbar, 'scroll', (event) =>
127 | @removePopover()
128 |
129 | verticalScrollbar = textEditorElement.querySelector('.vertical-scrollbar')
130 |
131 | if verticalScrollbar?
132 | @getSubAtom().add verticalScrollbar, 'scroll', (event) =>
133 | @removePopover()
134 |
135 | # Ticket #107 - Mouseout isn't generated until the mouse moves, even when scrolling (with the keyboard or
136 | # mouse). If the element goes out of the view in the meantime, its HTML element disappears, never removing
137 | # it.
138 | editor.onDidDestroy () =>
139 | @removePopover()
140 |
141 | editor.onDidStopChanging () =>
142 | @removePopover()
143 |
144 | ###*
145 | * Shows a popover containing the documentation of the specified element located at the specified location.
146 | *
147 | * @param {TextEditor} editor TextEditor containing the elemment.
148 | * @param {string} selector The selector to search for.
149 | * @param {Point} bufferPosition The cursor location the element is at.
150 | * @param {int} delay How long to wait before the popover shows up.
151 | * @param {int} fadeInTime The amount of time to take to fade in the tooltip.
152 | ###
153 | showPopoverFor: (editor, selector, bufferPosition, delay = 500, fadeInTime = 100) ->
154 | name = $(selector).text()
155 |
156 | successHandler = (tooltipText) =>
157 | @removePopover()
158 |
159 | if tooltipText?.length > 0
160 | popoverElement = @getPopoverElementFromSelector(selector)
161 |
162 | @attachedPopover = @service.createAttachedPopover(popoverElement)
163 | @attachedPopover.setText('' + tooltipText + '
')
164 | @attachedPopover.showAfter(delay, fadeInTime)
165 |
166 | failureHandler = () =>
167 | return
168 |
169 | @fetchTooltipForWord(editor, bufferPosition, name).then(successHandler, failureHandler)
170 |
171 | ###*
172 | * Removes the popover, if it is displayed.
173 | ###
174 | removePopover: () ->
175 | if @pendingPromise?
176 | @pendingPromise.reject()
177 | @pendingPromise = null
178 |
179 | if @attachedPopover
180 | @attachedPopover.dispose()
181 | @attachedPopover = null
182 |
183 | ###*
184 | * Retrieves a tooltip for the word given.
185 | *
186 | * @param {TextEditor} editor TextEditor to search for namespace of term.
187 | * @param {Point} bufferPosition The cursor location the term is at.
188 | * @param {string} name The name of the element to retrieve the tooltip for.
189 | *
190 | * @return {Promise}
191 | ###
192 | fetchTooltipForWord: (editor, bufferPosition, name) ->
193 | return new Promise (resolve, reject) =>
194 | @pendingPromise = {
195 | reject: reject
196 | }
197 |
198 | successHandler = (tooltipText) =>
199 | @pendingPromise = null
200 | resolve(tooltipText)
201 | return
202 |
203 | failureHandler = () =>
204 | @pendingPromise = null
205 | reject()
206 | return
207 |
208 | return @getTooltipForWord(editor, bufferPosition, name).then(successHandler, failureHandler)
209 |
210 | ###*
211 | * Retrieves a tooltip for the word given.
212 | *
213 | * @param {TextEditor} editor TextEditor to search for namespace of term.
214 | * @param {Point} bufferPosition The cursor location the term is at.
215 | * @param {string} name The name of the element to retrieve the tooltip for.
216 | *
217 | * @return {Promise}
218 | ###
219 | getTooltipForWord: (editor, bufferPosition, name) ->
220 | throw new Error("This method is abstract and must be implemented!")
221 |
222 | ###*
223 | * Gets the correct selector when a selector is clicked.
224 | * @param {jQuery.Event} event A jQuery event.
225 | * @return {object|null} A selector to be used with jQuery.
226 | ###
227 | getSelectorFromEvent: (event) ->
228 | return event.currentTarget
229 |
230 | ###*
231 | * Gets the correct element to attach the popover to from the retrieved selector.
232 | * @param {jQuery.Event} event A jQuery event.
233 | * @return {object|null} A selector to be used with jQuery.
234 | ###
235 | getPopoverElementFromSelector: (selector) ->
236 | return selector
237 |
238 | ###*
239 | * @return {Object}
240 | ###
241 | getSubAtom: () ->
242 | if not @subAtom
243 | @subAtom = new SubAtom()
244 |
245 | return @subAtom
246 |
--------------------------------------------------------------------------------
/lib/ClassConstantProvider.coffee:
--------------------------------------------------------------------------------
1 | Utility = require './Utility'
2 | AbstractProvider = require './AbstractProvider'
3 |
4 | module.exports =
5 |
6 | ##*
7 | # Provides tooltips for member constants.
8 | ##
9 | class ClassConstantProvider extends AbstractProvider
10 | ###*
11 | * @inheritdoc
12 | ###
13 | hoverEventSelectors: '.syntax--constant.syntax--other.syntax--class'
14 |
15 | ###*
16 | * @inheritdoc
17 | ###
18 | getTooltipForWord: (editor, bufferPosition, name) ->
19 | return new Promise (resolve, reject) =>
20 | failureHandler = () =>
21 | reject()
22 |
23 | resultingTypeSuccessHandler = (types) =>
24 | if types.length == 0
25 | reject()
26 | return
27 |
28 | successHandler = (classInfoArray) =>
29 | for classInfo in classInfoArray
30 | if name of classInfo.constants
31 | tooltipText = Utility.buildTooltipForConstant(classInfo.constants[name])
32 |
33 | resolve(tooltipText)
34 | return
35 |
36 | reject()
37 |
38 | promises = []
39 |
40 | for type in types
41 | promises.push @service.getClassInfo(type)
42 |
43 | Promise.all(promises).then(successHandler, failureHandler)
44 |
45 | return @service.getResultingTypesAt(editor, bufferPosition, true).then(
46 | resultingTypeSuccessHandler,
47 | failureHandler
48 | )
49 |
--------------------------------------------------------------------------------
/lib/ClassProvider.coffee:
--------------------------------------------------------------------------------
1 | Utility = require './Utility'
2 | AbstractProvider = require './AbstractProvider'
3 |
4 | module.exports =
5 |
6 | ##*
7 | # Provides tooltips for classes, traits, interfaces, ...
8 | ##
9 | class ClassProvider extends AbstractProvider
10 | ###*
11 | * @inheritdoc
12 | ###
13 | hoverEventSelectors: '.syntax--entity.syntax--name.syntax--type.syntax--class, .syntax--entity.syntax--inherited-class, .syntax--support.syntax--namespace, .syntax--support.syntax--class'
14 |
15 | ###*
16 | * @inheritdoc
17 | ###
18 | getTooltipForWord: (editor, bufferPosition, name) ->
19 | return new Promise (resolve, reject) =>
20 | scopeChain = editor.scopeDescriptorForBufferPosition(bufferPosition).getScopeChain()
21 |
22 | failureHandler = () =>
23 | reject()
24 |
25 | successHandler = (currentClassName) =>
26 | successHandler = (classInfo) =>
27 | tooltipText = Utility.buildTooltipForClasslike(classInfo)
28 |
29 | resolve(tooltipText)
30 |
31 | firstPromise = null
32 |
33 | # Don't attempt to resolve class names in use statements. Note that scope descriptors for trait use
34 | # statements and actual "import" use statements are the same, so we have no choice but to use class
35 | # information for this: if we are inside a class, we can't be looking at a use statement.
36 | if scopeChain.indexOf('.support.other.namespace.use') == -1 or currentClassName?
37 | firstPromise = @service.resolveTypeAt(editor, bufferPosition, name, 'classlike')
38 |
39 | else
40 | firstPromise = new Promise (resolve, reject) ->
41 | resolve(name)
42 |
43 | firstPromiseHandler = (name) =>
44 | return @service.getClassInfo(name).then(successHandler, failureHandler)
45 |
46 | return firstPromise.then(firstPromiseHandler, failureHandler)
47 |
48 | return @service.determineCurrentClassName(editor, bufferPosition).then(successHandler, failureHandler)
49 |
50 | ###*
51 | * @inheritdoc
52 | ###
53 | getSelectorFromEvent: (event) ->
54 | return @getClassSelectorFromEvent(event)
55 |
56 | ###*
57 | * Gets the correct selector for the class or namespace that is part of the specified event.
58 | *
59 | * @param {jQuery.Event} event A jQuery event.
60 | *
61 | * @return {object|null} A selector to be used with jQuery.
62 | ###
63 | getClassSelectorFromEvent: (event) ->
64 | selector = event.currentTarget
65 |
66 | $ = require 'jquery'
67 |
68 | if $(selector).parent().hasClass('syntax--function syntax--argument')
69 | return $(selector).parent().children('.syntax--namespace, .syntax--class:not(.syntax--operator):not(.syntax--constant)')
70 |
71 | if $(selector).prev().hasClass('syntax--namespace') && $(selector).hasClass('syntax--class')
72 | return $([$(selector).prev()[0], selector])
73 |
74 | if $(selector).next().hasClass('syntax--class') && $(selector).hasClass('syntax--namespace')
75 | return $([selector, $(selector).next()[0]])
76 |
77 | if $(selector).prev().hasClass('syntax--namespace') || $(selector).next().hasClass('syntax--inherited-class')
78 | return $(selector).parent().children('.syntax--namespace, .syntax--inherited-class')
79 |
80 | if $(selector).next().hasClass('syntax--constant') && $(selector).hasClass('syntax--namespace')
81 | return null
82 |
83 | return selector
84 |
85 | ###*
86 | * @inheritdoc
87 | ###
88 | getPopoverElementFromSelector: (selector) ->
89 | $ = require 'jquery'
90 |
91 | # getSelectorFromEvent can return multiple items because namespaces and class names are different HTML elements.
92 | # We have to select one to attach the popover to.
93 | array = $(selector).toArray()
94 | return array[array.length - 1]
95 |
--------------------------------------------------------------------------------
/lib/ConstantProvider.coffee:
--------------------------------------------------------------------------------
1 | Utility = require './Utility'
2 | AbstractProvider = require './AbstractProvider'
3 |
4 | module.exports =
5 |
6 | ##*
7 | # Provides tooltips for member methods.
8 | ##
9 | class MethodProvider extends AbstractProvider
10 | ###*
11 | * @inheritdoc
12 | ###
13 | hoverEventSelectors: '.syntax--constant.syntax--other.syntax--php, .syntax--support.syntax--other.syntax--namespace.syntax--php'
14 |
15 | ###*
16 | * @inheritdoc
17 | ###
18 | getTooltipForWord: (editor, bufferPosition, name) ->
19 | return new Promise (resolve, reject) =>
20 | failureHandler = () =>
21 | reject()
22 |
23 | resolveTypeHandler = (type) =>
24 | successHandler = (constants) =>
25 | if type?[0] != '\\'
26 | type = '\\' + type
27 |
28 | if constants and type of constants
29 | resolve(Utility.buildTooltipForConstant(constants[type]))
30 | return
31 |
32 | reject()
33 |
34 | return @service.getGlobalConstants().then(successHandler, failureHandler)
35 |
36 | return @service.resolveType(editor.getPath(), bufferPosition.row + 1, name, 'constant').then(
37 | resolveTypeHandler,
38 | failureHandler
39 | )
40 |
41 | ###*
42 | * @inheritdoc
43 | ###
44 | getSelectorFromEvent: (event) ->
45 | return @getClassSelectorFromEvent(event)
46 |
47 | ###*
48 | * Gets the correct selector for the constant that is part of the specified event.
49 | *
50 | * @param {jQuery.Event} event A jQuery event.
51 | *
52 | * @return {object|null} A selector to be used with jQuery.
53 | ###
54 | getClassSelectorFromEvent: (event) ->
55 | selector = event.currentTarget
56 |
57 | $ = require 'jquery'
58 |
59 | if $(selector).prev().hasClass('namespace') && $(selector).hasClass('constant')
60 | return $([$(selector).prev()[0], selector])
61 |
62 | if $(selector).next().hasClass('constant') && $(selector).hasClass('namespace')
63 | return $([selector, $(selector).next()[0]])
64 |
65 | return $(selector)
66 |
67 | ###*
68 | * @inheritdoc
69 | ###
70 | getPopoverElementFromSelector: (selector) ->
71 | $ = require 'jquery'
72 |
73 | # getSelectorFromEvent can return multiple items because namespaces and constants are different HTML elements.
74 | # We have to select one to attach the popover to.
75 | array = $(selector).toArray()
76 | return array[array.length - 1]
77 |
--------------------------------------------------------------------------------
/lib/FunctionDefinitionProvider.coffee:
--------------------------------------------------------------------------------
1 | Utility = require './Utility'
2 | AbstractProvider = require './AbstractProvider'
3 |
4 | module.exports =
5 |
6 | ##*
7 | # Provides tooltips on function and method definitions.
8 | ##
9 | class FunctionDefinitionProvider extends AbstractProvider
10 | ###*
11 | * @inheritdoc
12 | ###
13 | hoverEventSelectors: '.syntax--entity.syntax--name.syntax--function, .syntax--support.syntax--function.syntax--magic'
14 |
15 | ###*
16 | * @inheritdoc
17 | ###
18 | getTooltipForWord: (editor, bufferPosition, name) ->
19 | return new Promise (resolve, reject) =>
20 | failureHandler = () =>
21 | reject()
22 |
23 | successHandler = (currentClassName) =>
24 | if currentClassName?
25 | successHandler = (classInfo) =>
26 | if name of classInfo.methods
27 | tooltipText = Utility.buildTooltipForFunction(classInfo.methods[name])
28 |
29 | resolve(tooltipText)
30 | return
31 |
32 | reject()
33 |
34 | return @service.getClassInfo(currentClassName).then(successHandler, failureHandler)
35 |
36 | else
37 | successHandler = (functions) =>
38 | if functions and name of functions
39 | resolve(Utility.buildTooltipForFunction(functions[name]))
40 | return
41 |
42 | reject()
43 |
44 | return @service.getGlobalFunctions().then(successHandler, failureHandler)
45 |
46 | return @service.determineCurrentClassName(editor, bufferPosition).then(successHandler, failureHandler)
47 |
--------------------------------------------------------------------------------
/lib/FunctionProvider.coffee:
--------------------------------------------------------------------------------
1 | Utility = require './Utility'
2 | AbstractProvider = require './AbstractProvider'
3 |
4 | module.exports =
5 |
6 | ##*
7 | # Provides tooltips for global functions.
8 | ##
9 | class FunctionProvider extends AbstractProvider
10 | ###*
11 | * @inheritdoc
12 | ###
13 | hoverEventSelectors: '.syntax--function-call:not(.syntax--object):not(.syntax--static), .syntax--support.syntax--function:not(.syntax--magic)'
14 |
15 | ###*
16 | * @inheritdoc
17 | ###
18 | getTooltipForWord: (editor, bufferPosition, name) ->
19 | return new Promise (resolve, reject) =>
20 | failureHandler = () =>
21 | reject()
22 |
23 | resolveTypeHandler = (type) =>
24 | successHandler = (functions) =>
25 | if type?[0] != '\\'
26 | type = '\\' + type
27 |
28 | if functions and type of functions
29 | resolve(Utility.buildTooltipForFunction(functions[type]))
30 | return
31 |
32 | reject()
33 |
34 | return @service.getGlobalFunctions().then(successHandler, failureHandler)
35 |
36 | return @service.resolveType(editor.getPath(), bufferPosition.row + 1, name, 'function').then(
37 | resolveTypeHandler,
38 | failureHandler
39 | )
40 |
--------------------------------------------------------------------------------
/lib/Main.coffee:
--------------------------------------------------------------------------------
1 | module.exports =
2 | ###*
3 | * List of tooltip providers.
4 | ###
5 | providers: []
6 |
7 | ###*
8 | * Activates the package.
9 | ###
10 | activate: ->
11 |
12 | ###*
13 | * Deactivates the package.
14 | ###
15 | deactivate: ->
16 | @deactivateProviders()
17 |
18 | ###*
19 | * Activates the providers using the specified service.
20 | ###
21 | activateProviders: (service) ->
22 | ClassProvider = require './ClassProvider'
23 | MethodProvider = require './MethodProvider'
24 | PropertyProvider = require './PropertyProvider'
25 | FunctionProvider = require './FunctionProvider'
26 | ConstantProvider = require './ConstantProvider'
27 | ClassConstantProvider = require './ClassConstantProvider'
28 | FunctionDefinitionProvider = require './FunctionDefinitionProvider'
29 |
30 | @providers = []
31 | @providers.push new ClassProvider()
32 | @providers.push new MethodProvider()
33 | @providers.push new FunctionProvider()
34 | @providers.push new PropertyProvider()
35 | @providers.push new FunctionDefinitionProvider()
36 |
37 | # The selector from the constant provider will still match class constants due to the way SubAtom does its
38 | # class selector checks. However, the reverse doesn't hold so if we add the class constant provider first,
39 | # we will not run into problems.
40 | @providers.push new ClassConstantProvider()
41 | @providers.push new ConstantProvider()
42 |
43 | for provider in @providers
44 | provider.activate(service)
45 |
46 | ###*
47 | * Deactivates any active providers.
48 | ###
49 | deactivateProviders: () ->
50 | for provider in @providers
51 | provider.deactivate()
52 |
53 | @providers = []
54 |
55 | ###*
56 | * Sets the php-integrator service.
57 | *
58 | * @param {mixed} service
59 | ###
60 | setService: (service) ->
61 | @activateProviders(service)
62 |
63 | {Disposable} = require 'atom'
64 |
65 | return new Disposable => @deactivateProviders()
66 |
--------------------------------------------------------------------------------
/lib/MethodProvider.coffee:
--------------------------------------------------------------------------------
1 | Utility = require './Utility'
2 | AbstractProvider = require './AbstractProvider'
3 |
4 | module.exports =
5 |
6 | ##*
7 | # Provides tooltips for global constants.
8 | ##
9 | class ClassProvider extends AbstractProvider
10 | ###*
11 | * @inheritdoc
12 | ###
13 | hoverEventSelectors: '.syntax--function-call.syntax--object, .syntax--function-call.syntax--static'
14 |
15 | ###*
16 | * @inheritdoc
17 | ###
18 | getTooltipForWord: (editor, bufferPosition, name) ->
19 | return new Promise (resolve, reject) =>
20 | failureHandler = () =>
21 | reject()
22 |
23 | resultingTypeSuccessHandler = (types) =>
24 | if types.length == 0
25 | reject()
26 | return
27 |
28 | successHandler = (classInfoArray) =>
29 | for classInfo in classInfoArray
30 | if name of classInfo.methods
31 | tooltipText = Utility.buildTooltipForFunction(classInfo.methods[name])
32 |
33 | resolve(tooltipText)
34 | return
35 |
36 | reject()
37 |
38 | promises = []
39 |
40 | for type in types
41 | promises.push @service.getClassInfo(type)
42 |
43 | Promise.all(promises).then(successHandler, failureHandler)
44 |
45 | return @service.getResultingTypesAt(editor, bufferPosition, true).then(
46 | resultingTypeSuccessHandler,
47 | failureHandler
48 | )
49 |
--------------------------------------------------------------------------------
/lib/PropertyProvider.coffee:
--------------------------------------------------------------------------------
1 | Utility = require './Utility'
2 | AbstractProvider = require './AbstractProvider'
3 |
4 | module.exports =
5 |
6 | ##*
7 | # Provides tooltips for member properties.
8 | ##
9 | class PropertyProvider extends AbstractProvider
10 | ###*
11 | * @inheritdoc
12 | ###
13 | hoverEventSelectors: '.syntax--property'
14 |
15 | ###*
16 | * @inheritdoc
17 | ###
18 | getTooltipForWord: (editor, bufferPosition, name) ->
19 | return new Promise (resolve, reject) =>
20 | failureHandler = () =>
21 | reject()
22 |
23 | resultingTypeSuccessHandler = (types) =>
24 | if types.length == 0
25 | reject()
26 | return
27 |
28 | successHandler = (classInfoArray) =>
29 | for classInfo in classInfoArray
30 | if name of classInfo.properties
31 | tooltipText = Utility.buildTooltipForProperty(classInfo.properties[name])
32 |
33 | resolve(tooltipText)
34 | return
35 |
36 | reject()
37 |
38 | promises = []
39 |
40 | for type in types
41 | promises.push @service.getClassInfo(type)
42 |
43 | Promise.all(promises).then(successHandler, failureHandler)
44 |
45 | return @service.getResultingTypesAt(editor, bufferPosition, true).then(
46 | resultingTypeSuccessHandler,
47 | failureHandler
48 | )
49 |
--------------------------------------------------------------------------------
/lib/Utility.coffee:
--------------------------------------------------------------------------------
1 | Utility = require './Utility'
2 |
3 | module.exports =
4 | ###*
5 | * Builds a tooltip for a classlike structural element.
6 | *
7 | * @param {Object} value
8 | *
9 | * @return {string}
10 | ###
11 | buildTooltipForClasslike: (value) ->
12 | description = ''
13 |
14 | # Show the summary (short description).
15 | description += ''
16 | description += (if value.shortDescription then value.shortDescription else '(No documentation available)')
17 | description += '
'
18 |
19 | # Show the (long) description.
20 | if value.longDescription?.length > 0
21 | description += ''
22 | description += "
Description
"
23 | description += "
" + value.longDescription + "
"
24 | description += "
"
25 |
26 | # Shwo the FQCN.
27 | description += ''
28 | description += "
Full Name
"
29 | description += "
" + value.name + "
"
30 | description += "
"
31 |
32 | # Show the type.
33 | type = ''
34 |
35 | if value.type == 'class'
36 | type = (if value.isAbstract then 'Abstract ' else '') + 'Class'
37 |
38 | else if value.type == 'trait'
39 | type = 'Trait'
40 |
41 | else if value.type == 'interface'
42 | type = 'Interface'
43 |
44 | description += ''
45 | description += "
Type
"
46 | description += "
" + type + "
"
47 | description += "
"
48 |
49 | return description
50 |
51 | ###*
52 | * Builds a tooltip for a function.
53 | *
54 | * @param {Object} value
55 | *
56 | * @return {string}
57 | ###
58 | buildTooltipForFunction: (value) ->
59 | description = ""
60 |
61 | # Show the summary (short description).
62 | description += ''
63 | description += (if value.shortDescription then value.shortDescription else '(No documentation available)')
64 | description += '
'
65 |
66 | # Show the (long) description.
67 | if value.longDescription?.length > 0
68 | description += ''
69 | description += "
Description
"
70 | description += "
" + value.longDescription + "
"
71 | description += "
"
72 |
73 | # Show the parameters the method has.
74 | parametersDescription = ""
75 |
76 | for param in value.parameters
77 | parametersDescription += ''
78 |
79 | parametersDescription += '• '
80 |
81 | if param.isOptional
82 | parametersDescription += '['
83 |
84 | if param.isReference
85 | parametersDescription += '&'
86 |
87 | if param.isVariadic
88 | parametersDescription += '...'
89 |
90 | parametersDescription += '$' + param.name
91 |
92 | if param.isOptional
93 | parametersDescription += ']'
94 |
95 | parametersDescription += " | "
96 |
97 | parametersDescription += '' + (if param.types.length > 0 then @buildTypeSpecificationFromTypeArray(param.types) else ' ') + ' | '
98 | parametersDescription += '' + (if param.description then param.description else ' ') + ' | '
99 |
100 | parametersDescription += "
"
101 |
102 | if parametersDescription.length > 0
103 | description += ''
104 | description += "
Parameters
"
105 | description += "
" + parametersDescription + "
"
106 | description += "
"
107 |
108 | returnValue = @buildTypeSpecificationFromTypeArray(value.returnTypes)
109 |
110 | returnDescription = ''
111 |
112 | if value.returnDescription
113 | returnDescription = ' — ' + value.returnDescription
114 |
115 | description += ''
116 | description += '
Returns
'
117 | description += '
' + returnValue + '' + returnDescription + '
'
118 | description += "
"
119 |
120 | # Show an overview of the exceptions the method can throw.
121 | throwsDescription = ""
122 |
123 | for exceptionType,thrownWhenDescription of value.throws
124 | throwsDescription += ""
125 | throwsDescription += "• " + exceptionType + ""
126 |
127 | if thrownWhenDescription
128 | throwsDescription += ' ' + thrownWhenDescription
129 |
130 | throwsDescription += "
"
131 |
132 | if throwsDescription.length > 0
133 | description += ''
134 | description += "
Throws
"
135 | description += "
" + throwsDescription + "
"
136 | description += "
"
137 |
138 | return description
139 |
140 | ###*
141 | * Builds a tooltip for a property.
142 | *
143 | * @param {Object} value
144 | *
145 | * @return {string}
146 | ###
147 | buildTooltipForProperty: (value) ->
148 | # Create a useful description to show in the tooltip.
149 | description = ''
150 |
151 | # Show the summary (short description).
152 | description += ''
153 | description += (if value.shortDescription then value.shortDescription else '(No documentation available)')
154 | description += '
'
155 |
156 | # Show the (long) description.
157 | if value.longDescription?.length > 0
158 | description += ''
159 | description += "
Description
"
160 | description += "
" + value.longDescription + "
"
161 | description += "
"
162 |
163 | returnValue = @buildTypeSpecificationFromTypeArray(value.types)
164 |
165 | returnDescription = ''
166 |
167 | if value.returnDescription
168 | returnDescription = ' — ' + value.returnDescription
169 |
170 | description += ''
171 | description += '
Type
'
172 | description += '
' + returnValue + '' + returnDescription + '
'
173 | description += "
"
174 |
175 | ###*
176 | * Builds a tooltip for a constant.
177 | *
178 | * @param {Object} value
179 | *
180 | * @return {string}
181 | ###
182 | buildTooltipForConstant: (value) ->
183 | # Create a useful description to show in the tooltip.
184 | description = ''
185 |
186 | # Show the summary (short description).
187 | description += ''
188 | description += (if value.shortDescription then value.shortDescription else '(No documentation available)')
189 | description += '
'
190 |
191 | # Show the (long) description.
192 | if value.longDescription?.length > 0
193 | description += ''
194 | description += "
Description
"
195 | description += "
" + value.longDescription + "
"
196 | description += "
"
197 |
198 | returnValue = @buildTypeSpecificationFromTypeArray(value.types)
199 |
200 | returnDescription = ''
201 |
202 | if value.returnDescription
203 | returnDescription = ' — ' + value.returnDescription
204 |
205 | description += ''
206 | description += '
Type
'
207 | description += '
' + returnValue + '' + returnDescription + '
'
208 | description += "
"
209 |
210 | return description
211 |
212 | ###*
213 | * @param {Array} typeArray
214 | *
215 | * @return {String}
216 | ###
217 | buildTypeSpecificationFromTypeArray: (typeArray) ->
218 | if typeArray.length == 0
219 | return '(Not known)'
220 |
221 | typeNames = typeArray.map (type) ->
222 | return type.type
223 |
224 | return typeNames.join('|')
225 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "php-integrator-tooltips-legacy-php56",
3 | "main": "./lib/Main",
4 | "version": "1.1.6",
5 | "description": "Shows tooltips (e.g. for methods and classes) in your PHP source code.",
6 | "repository": "php-integrator/atom-tooltips-legacy-php56",
7 | "license": "GPL-3.0",
8 | "engines": {
9 | "atom": ">=1.13.0 <2.0.0"
10 | },
11 | "consumedServices": {
12 | "php-integrator.service": {
13 | "versions": {
14 | "^2.0": "setService"
15 | }
16 | }
17 | },
18 | "dependencies": {
19 | "jquery": "~2.1.4",
20 | "sub-atom": "~1.0.0"
21 | },
22 | "keywords": [
23 | "php",
24 | "tooltips",
25 | "integrator",
26 | "integration",
27 | "php-integrator"
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/styles/main.less:
--------------------------------------------------------------------------------
1 | // The ui-variables file is provided by base themes provided by Atom.
2 | //
3 | // See https://github.com/atom/atom-dark-ui/blob/master/stylesheets/ui-variables.less
4 | // for a full listing of what's available.
5 | @import "ui-variables";
6 | @import "octicon-utf-codes";
7 |
8 | .php-integrator-tooltips-popover {
9 | padding-right: 1em;
10 |
11 | padding-top: 0.25em;
12 | padding-bottom: 0.25em;
13 |
14 | overflow-y: auto;
15 | max-height: 40em;
16 |
17 | .php-integrator-tooltips-parameter-name {
18 | font-weight: bold;
19 | }
20 |
21 | .php-integrator-tooltips-parameter-type {
22 | font-style: italic;
23 | }
24 |
25 | .php-integrator-tooltips-return-type {
26 | font-style: italic;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------