├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── lib ├── main.js ├── php-hyperclick-package-view.coffee └── php-hyperclick-package.coffee ├── menus └── php-hyperclick.cson ├── package.json ├── php ├── FQCN.php ├── getfilepath.php └── tests │ ├── Another │ └── World.php │ ├── FQCNTest.php │ ├── Hello │ ├── Comma.php │ ├── Separated.php │ └── World.php │ ├── TestClass.php │ └── World │ ├── Comma.php │ └── NewLineSeparated.php └── styles └── php-hyperclick.less /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.2.1 2 | 3 | * Updated README.md how to use without composer autoloader. 4 | 5 | # 1.2.0 6 | 7 | * Improved finding composer autoloader file path. Thank you @veger . For details @see https://github.com/harikt/php-hyperclick/pull/7 8 | 9 | # 1.1.0 10 | 11 | * Improved getting namespace when there were comments 12 | 13 | # 1.0.0 14 | 15 | * Intial version. 16 | 17 | # 0.4.0 18 | * Fixed #2 . Inform the user if vendor/autoload.php doesn't exists in root of project. 19 | 20 | # 0.3.1 21 | * Fix the clicked class namespace when they are on the same root namespace. 22 | Eg : `Cake\Core\Plugin` class contains a call to `Classloader`. Which is not referenced in the namespace. 23 | 24 | # 0.3.0 25 | * Moving to coffee script 26 | 27 | # 0.2.1 28 | 29 | * Bug fix adding necessary dependencies on the package.json. So hyperclick is installed automatically. 30 | * Update readme with gif showing the demo 31 | 32 | # 0.2.0 33 | 34 | * Version that got released. 35 | 36 | # 0.1.0 37 | 38 | * Initial version 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Hari KT 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-hyperclick package 2 | 3 | This package is no longer maintained for we have [Atom IDE PHP](https://github.com/atom/ide-php) which has more features. 4 | 5 | Open the class files when you trigger `ctrl` + `mouse left click`. 6 | 7 | ![How it works!](https://cloud.githubusercontent.com/assets/120454/12533819/51b6cd44-c264-11e5-855c-ecd6437ca43d.gif) 8 | 9 | ## Inspired by 10 | 11 | * [js-hyperclick](https://github.com/AsaAyers/js-hyperclick/) 12 | * [atom-autocomplete-php](https://github.com/Peekmo/atom-autocomplete-php) 13 | 14 | This works with the help of some dependencies 15 | 16 | * [Hyperclick](https://atom.io/packages/hyperclick) 17 | 18 | Optional dependency: 19 | 20 | * [Composer](https://getcomposer.org) a dependency manager for PHP 21 | 22 | ## Making composer an optional dependency 23 | 24 | Even though the class finding functionality is relied on composer, you can easily 25 | make the necessary change to make composer as optional dependency. 26 | 27 | The base working of the package is it tries to find the file `/vendor/autoload.php` 28 | which returns an autoloader object. It assumes the object has a method 29 | [findFile($class_name)](https://github.com/composer/composer/blob/c540dace8cceca12b1fa969fd9f58dcb7395d402/src/Composer/Autoload/ClassLoader.php#L307-L314). 30 | 31 | So if you are not using composer, keep a `vendor/autoload.php` file on the root 32 | of your project. 33 | 34 | ```php 35 | // vendor/autoload.php 36 | 37 | $autoloader = new YourAutoloader(); 38 | 39 | // Make sure there is findFile method which can return the path to the file when class name is passed 40 | 41 | return $autoloader; 42 | ``` 43 | 44 | ## Wishes 45 | 46 | * Learn coffee script and port 47 | * Improve all the ugly code 48 | 49 | ## Known Limitations 50 | 51 | * Must have `use` statement in classes. Else clicking on things like `new \Lib\Hello\World()` will not be opened. 52 | * May not work on windows 53 | * Other unknown bugs 54 | 55 | ## Thanks 56 | 57 | Special Thanks to 58 | 59 | * Marco Pivetta 60 | * Shameer C 61 | * Wouter J 62 | * Mark Hahn 63 | * Lee Dohm 64 | * Dylan R. E. Moonfire 65 | * Joel Clermont 66 | 67 | and to everyone who have helped knowingly/unknowingly to make this happen. 68 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | "use babel"; 2 | import cp from 'child_process'; 3 | import path from 'path'; 4 | // import "process" 5 | import { CompositeDisposable } from 'atom' 6 | 7 | var singleSuggestionProvider = { 8 | providerName:'php-hyperclick', 9 | getSuggestionForWord(textEditor: TextEditor, text: string, range: Range): HyperclickSuggestion { 10 | return { 11 | range, 12 | callback() { 13 | var args, ref1, ref2, relativePath, projectPath; 14 | 15 | // Get the current project path of the opened file. Thank you Dylan R. E. Moonfire 16 | // https://discuss.atom.io/t/project-folder-path-of-opened-file/24846/14?u=harikt 17 | ref2 = atom.project.relativizePath(textEditor.getPath()); 18 | projectPath = ref2[0]; 19 | 20 | args = [ 21 | path.resolve(__dirname, '../php/getfilepath.php'), 22 | text, 23 | textEditor.getPath(), 24 | projectPath 25 | ]; 26 | openFilePath = cp.spawnSync('php', args).output[1].toString('ascii'); 27 | if (openFilePath) { 28 | atom.workspace.open(openFilePath); 29 | } else { 30 | atom.notifications.addInfo('Unable to locate , errored with ' + openFilePath); 31 | } 32 | }, 33 | }; 34 | } 35 | } 36 | 37 | module.exports = { 38 | activate(state) { 39 | this.subscriptions = new CompositeDisposable() 40 | }, 41 | getProvider() { 42 | return singleSuggestionProvider; 43 | }, 44 | deactivate() { 45 | this.subscriptions.dispose() 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /lib/php-hyperclick-package-view.coffee: -------------------------------------------------------------------------------- 1 | path = require "path" 2 | fs = require "fs" 3 | child_process = require "child_process" 4 | 5 | module.exports = 6 | class PhpHyperclickPackageView 7 | constructor: (serializedState) -> 8 | # Create root element 9 | @element = document.createElement('div') 10 | @element.classList.add('php-hperclick-package') 11 | 12 | # Create message element 13 | message = document.createElement('div') 14 | message.textContent = "The PhpHyperclickPackage package is Alive! It's ALIVE!" 15 | message.classList.add('message') 16 | @element.appendChild(message) 17 | 18 | # Returns an object that can be retrieved when package is activated 19 | serialize: -> 20 | 21 | singleSuggestionProvider: => 22 | providerName: 'php-hyperclick' 23 | getSuggestionForWord: (textEditor, text, range) -> 24 | { 25 | range: range 26 | callback: -> 27 | args = undefined 28 | ref1 = undefined 29 | ref2 = undefined 30 | relativePath = undefined 31 | projectPath = undefined 32 | # Get the current project path of the opened file. Thank you Dylan R. E. Moonfire 33 | # https://discuss.atom.io/t/project-folder-path-of-opened-file/24846/14?u=harikt 34 | ref2 = atom.project.relativizePath(textEditor.getPath()) 35 | projectPath = ref2[0] 36 | args = [ 37 | path.resolve __dirname, '../php/getfilepath.php' 38 | text 39 | textEditor.getPath() 40 | projectPath 41 | ] 42 | `openFilePath = child_process.spawnSync('php', args).output[1].toString('ascii')` 43 | 44 | try 45 | if fs.lstatSync(openFilePath).isFile() 46 | atom.workspace.open openFilePath 47 | catch error 48 | atom.notifications.addError 'Error : ' + openFilePath 49 | return 50 | } 51 | 52 | # Tear down any state and detach 53 | destroy: -> 54 | @element.remove() 55 | 56 | getElement: -> 57 | @element 58 | -------------------------------------------------------------------------------- /lib/php-hyperclick-package.coffee: -------------------------------------------------------------------------------- 1 | PhpHyperclickPackageView = require './php-hyperclick-package-view' 2 | {CompositeDisposable} = require 'atom' 3 | 4 | module.exports = PhpHyperclickPackage = 5 | phpHyperclickPackageView: null 6 | modalPanel: null 7 | subscriptions: null 8 | 9 | activate: (state) -> 10 | @phpHyperclickPackageView = new PhpHyperclickPackageView(state.phpHyperclickPackageViewState) 11 | # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable 12 | @subscriptions = new CompositeDisposable 13 | 14 | getProvider: -> 15 | @phpHyperclickPackageView.singleSuggestionProvider() 16 | 17 | deactivate: -> 18 | @subscriptions.dispose() 19 | @phpHyperclickPackageView.destroy() 20 | 21 | serialize: -> 22 | phpHyperclickPackageViewState: @phpHyperclickPackageView.serialize() 23 | -------------------------------------------------------------------------------- /menus/php-hyperclick.cson: -------------------------------------------------------------------------------- 1 | # See https://atom.io/docs/latest/hacking-atom-package-word-count#menus for more details 2 | 'context-menu': 3 | 'atom-text-editor': [ 4 | { 5 | 'label': 'Toggle php-hyperclick' 6 | 'command': 'php-hyperclick:toggle' 7 | } 8 | ] 9 | 'menu': [ 10 | { 11 | 'label': 'Packages' 12 | 'submenu': [ 13 | 'label': 'php-hyperclick' 14 | 'submenu': [ 15 | { 16 | 'label': 'Toggle' 17 | 'command': 'php-hyperclick:toggle' 18 | } 19 | ] 20 | ] 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "php-hyperclick", 3 | "author": "Hari KT", 4 | "main": "./lib/php-hyperclick-package", 5 | "version": "1.2.1", 6 | "description": "Hyperclick provider for PHP. Open file when classname is clicked", 7 | "keywords": [ 8 | "hyperclick", 9 | "php" 10 | ], 11 | "repository": "https://github.com/harikt/php-hyperclick", 12 | "license": "MIT", 13 | "engines": { 14 | "atom": ">=1.0.0 <2.0.0" 15 | }, 16 | "providedServices": { 17 | "hyperclick.provider": { 18 | "versions": { 19 | "0.0.0": "getProvider" 20 | } 21 | } 22 | }, 23 | "dependencies": { 24 | "hyperclick": ">=0.0.20" 25 | }, 26 | "devDependencies": { 27 | "hyperclick-interfaces": "0.0.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /php/FQCN.php: -------------------------------------------------------------------------------- 1 | currentNamespace .= $token[1]; 39 | } 40 | if ($useFlag && ! $asFlag) { 41 | $className .= $token[1]; 42 | } 43 | if ($asFlag) { 44 | $shortName = $token[1]; 45 | $asFlag = 0; 46 | } 47 | // start keeping class 48 | } else { 49 | if ($useFlag && ($token == ';' || $token == ',')) { 50 | $className = trim($className); 51 | if (! $shortName) { 52 | try { 53 | $shortName = $this->getShortName($className); 54 | } catch (\Exception $e) { 55 | // Errored 56 | continue; 57 | } 58 | } 59 | $result[$shortName] = $className; 60 | if ($token == ',') { 61 | $useFlag = 1; 62 | } 63 | $shortName = $className = ''; 64 | } 65 | /** 66 | * End of namespace 67 | */ 68 | if ($token == ';' && $useNamespace == 1) 69 | { 70 | $useNamespace = 0; 71 | } 72 | } 73 | } 74 | return $result; 75 | } 76 | 77 | public function getNamespace() 78 | { 79 | return trim($this->currentNamespace); 80 | } 81 | 82 | protected function getShortName($className) 83 | { 84 | $reflex = new \ReflectionClass($className); 85 | $shortName = $reflex->getShortName(); 86 | return $shortName; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /php/getfilepath.php: -------------------------------------------------------------------------------- 1 | getAllUseStatements($contents); 48 | if (array_key_exists($class, $useClasses)) { 49 | echo $loader->findFile($useClasses[$class]); 50 | 51 | return true; 52 | } 53 | 54 | // Try using current namespace 55 | $namespace = $fqns->getNamespace(); 56 | if ($namespace) { 57 | $foundFile = $loader->findFile($namespace.'\\'.$class); 58 | if ($foundFile) { 59 | echo $foundFile; 60 | 61 | return true; 62 | } 63 | } 64 | 65 | // Try using global namespace 66 | $foundFile = $loader->findFile($class); 67 | if ($foundFile) { 68 | echo $foundFile; 69 | 70 | return true; 71 | } 72 | 73 | return false; 74 | } 75 | -------------------------------------------------------------------------------- /php/tests/Another/World.php: -------------------------------------------------------------------------------- 1 | 'Hello\World', 16 | 'AnotherWorld' => 'Another\World', 17 | 'Comma' => 'Hello\Comma', 18 | 'Separated' => 'Hello\Separated', 19 | 'WorldComma' => 'World\Comma', 20 | 'NewLineSeparated' => 'World\NewLineSeparated' 21 | ); 22 | $fqcn = new Hkt\FQCN(); 23 | $contents = file_get_contents(__DIR__ . '/TestClass.php'); 24 | it("expected and returned the same array", $expected == $fqcn->getAllUseStatements($contents)); 25 | 26 | $contents = file_get_contents(__DIR__ . '/Another/World.php'); 27 | $fqns = new Hkt\FQCN(); 28 | $fqns->getAllUseStatements($contents); 29 | it("Expected and return the same namespace Another", 'Another' == $fqns->getNamespace()); 30 | -------------------------------------------------------------------------------- /php/tests/Hello/Comma.php: -------------------------------------------------------------------------------- 1 |