├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── LICENSE-atom-autocomplete-php ├── README.md ├── lib ├── AbstractProvider.coffee ├── ClassConstantProvider.coffee ├── ClassProvider.coffee ├── ConstantProvider.coffee ├── FunctionDefinitionProvider.coffee ├── FunctionProvider.coffee ├── Main.coffee ├── MethodProvider.coffee ├── PropertyProvider.coffee └── Utility.coffee ├── package.json └── styles └── main.less /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | indent_style = space 8 | indent_size = 4 9 | charset = utf-8 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.1.6 2 | * Rename package to demarcate legacy status. 3 | 4 | ## 1.1.5 5 | * Fix tooltips for use statements not always working in Atom >= 1.13. 6 | 7 | ## 1.1.4 8 | * Fix tooltips for FQCN's not working. 9 | 10 | ## 1.1.3 11 | * Fix tooltips no longer working due to updated syntax class selectors. 12 | 13 | ## 1.1.2 14 | * Fix deprecations. 15 | 16 | ## 1.1.1 17 | * Ensure the subAtom property is always initialized. 18 | 19 | ## 1.1.0 (base 2.0.0) 20 | * The information displayed has been tweaked. 21 | * Fix navigation to unqualified global constants not working. 22 | * Fix navigation to unqualified global functions not working. 23 | * Fix navigation to global constants imported using use statements not working. 24 | * Fix navigation to global functions imported using use statements not working. 25 | * Fix tooltips for qualified global constants with namespace prefix not working. 26 | * Fix tooltips for qualified global functions with namespace prefix not working. 27 | 28 | ## 1.0.4 29 | * Rename the package and repository. 30 | 31 | ## 1.0.3 32 | * Fix tooltips not working on built-in PHP functions - properly this time. 33 | 34 | ## 1.0.2 35 | * Fix tooltips not working on built-in PHP functions. 36 | 37 | ## 1.0.1 38 | * Fix the version specifier not being compatible with newer versions of the base service. 39 | 40 | ## 1.0.0 (base 1.0.0) 41 | * Tweak the styling of the return block a bit. 42 | * The return section of tooltips will always be shown, regardless of whether the type is known or not. 43 | * Unknown return types will now no longer be shown as 'mixed', which makes it clearer to the user that documentation is missing. 44 | 45 | ## 0.6.1 (base 0.9.0) 46 | * Updated to use the most recent version of the base service. 47 | 48 | ## 0.6.0 (base 0.8.0) 49 | * A couple of tooltip providers have become more asynchronous, improving responsiveness. 50 | 51 | ## 0.5.0 (base 0.7.0) 52 | * Tooltip fetching is now mostly asynchronous, which should result in less minor hickups and freezes. 53 | * Class names after the class keyword (to start the definition) will now also show a tooltip, much like function definitions. 54 | 55 | ## 0.4.2 56 | * Fixed the tooltip not showing when hovering over magic methods such as `__construct`. 57 | 58 | ## 0.4.1 59 | * Catch exceptions properly. 60 | 61 | ## 0.4.0 (base 0.6.0) 62 | * Minor bugfixes. 63 | * Tooltips will now show up when hovering over function and method definitions as well. This is useful when you are inheriting documentation, so you can view what is actually inherited. 64 | 65 | ## 0.3.1 (base 0.5.0) 66 | * Updated to work with the most recent service from the base package. 67 | 68 | ## 0.3.0 (base 0.4.0) 69 | * Added tooltips for class and global constants. 70 | * Fixed error `Cannot read property 'length' of undefined` being thrown sometimes when there was a property and a method with the same name. 71 | 72 | ## 0.2.1 73 | * Wait for the language-php package to become activated on startup. 74 | 75 | ## 0.2.0 76 | * Tooltips are now displayed for global functions. `[1]` 77 | 78 | `[1]` Note that the built-in PHP functions don't have documentation that can be retrieved via reflection, so this only applies to user defined functions at the moment. 79 | 80 | ## 0.1.0 81 | * Initial release. 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This program is free software: you can redistribute it and/or modify 2 | it under the terms of the GNU General Public License as published by 3 | the Free Software Foundation, either version 3 of the License, or 4 | (at your option) any later version. 5 | 6 | This program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . 13 | -------------------------------------------------------------------------------- /LICENSE-atom-autocomplete-php: -------------------------------------------------------------------------------- 1 | This project was forked from atom-autocomplete-php, thus the original code base 2 | was licensed under the MIT license. It can still be found at [1]. The original 3 | license is located below. 4 | 5 | [1] https://github.com/Peekmo/atom-autocomplete-php 6 | 7 | The MIT License (MIT) 8 | 9 | Copyright (c) 2014-2015 Axel Anceau 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 | ![GPLv3 Logo](http://gplv3.fsf.org/gplv3-127x51.png) 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 | --------------------------------------------------------------------------------