Skip to content
This repository was archived by the owner on May 5, 2018. It is now read-only.

Commit a95fbbd

Browse files
committed
Initial commit with some very (VERY) rudimentary getter-setter generation. Far from finished and less than ideal. Barely usable at this point.
0 parents  commit a95fbbd

9 files changed

+402
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.DS_Store
2+
npm-debug.log
3+
node_modules

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
## 0.1.0
2+
* Initial release.

LICENSE

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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 <http://www.gnu.org/licenses/>.

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# php-integrator-refactoring
2+
3+
This package provides refactoring capabilities for your PHP source code using [PHP Integrator](https://github.com/Gert-dev/php-integrator-base).
4+
5+
**Note that the [php-integrator-base](https://github.com/Gert-dev/php-integrator-base) package is required and needs to be set up correctly for this package to function correctly.**
6+
7+
What is included?
8+
* Getter and setter generation.
9+
10+
Regarding donations: they were not my primary intention when releasing this project as open source, but I do accept them and am very grateful for any donation you may give. A link is provided on the readme of the [php-integrator-base](https://github.com/Gert-dev/php-integrator-base) package.
11+
12+
![GPLv3 Logo](http://gplv3.fsf.org/gplv3-127x51.png)

lib/AbstractProvider.coffee

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
module.exports =
2+
3+
##*
4+
# Base class for providers.
5+
##
6+
class AbstractProvider
7+
###*
8+
* The service (that can be used to query the source code and contains utility methods).
9+
###
10+
service: null
11+
12+
###*
13+
* Constructor.
14+
###
15+
constructor: () ->
16+
17+
18+
###*
19+
* Initializes this provider.
20+
*
21+
* @param {mixed} service
22+
###
23+
activate: (@service) ->
24+
dependentPackage = 'language-php'
25+
26+
# It could be that the dependent package is already active, in that case we can continue immediately. If not,
27+
# we'll need to wait for the listener to be invoked
28+
if atom.packages.isPackageActive(dependentPackage)
29+
@doActualInitialization()
30+
31+
atom.packages.onDidActivatePackage (packageData) =>
32+
return if packageData.name != dependentPackage
33+
34+
@doActualInitialization()
35+
36+
atom.packages.onDidDeactivatePackage (packageData) =>
37+
return if packageData.name != dependentPackage
38+
39+
@deactivate()
40+
41+
###*
42+
* Does the actual initialization.
43+
###
44+
doActualInitialization: () ->
45+
atom.workspace.observeTextEditors (editor) =>
46+
if /text.html.php$/.test(editor.getGrammar().scopeName)
47+
@registerEvents(editor)
48+
49+
# When you go back to only have one pane the events are lost, so need to re-register.
50+
atom.workspace.onDidDestroyPane (pane) =>
51+
panes = atom.workspace.getPanes()
52+
53+
if panes.length == 1
54+
@registerEventsForPane(panes[0])
55+
56+
# Having to re-register events as when a new pane is created the old panes lose the events.
57+
atom.workspace.onDidAddPane (observedPane) =>
58+
panes = atom.workspace.getPanes()
59+
60+
for pane in panes
61+
if pane != observedPane
62+
@registerEventsForPane(pane)
63+
64+
###*
65+
* Registers the necessary event handlers for the editors in the specified pane.
66+
*
67+
* @param {Pane} pane
68+
###
69+
registerEventsForPane: (pane) ->
70+
for paneItem in pane.items
71+
if atom.workspace.isTextEditor(paneItem)
72+
if /text.html.php$/.test(paneItem.getGrammar().scopeName)
73+
@registerEvents(paneItem)
74+
75+
###*
76+
* Deactives the provider.
77+
###
78+
deactivate: () ->
79+
80+
81+
###*
82+
* Registers the necessary event handlers.
83+
*
84+
* @param {TextEditor} editor TextEditor to register events to.
85+
###
86+
registerEvents: (editor) ->

lib/GetterSetterProvider.coffee

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
AbstractProvider = require './AbstractProvider'
2+
3+
SelectionView = require './GetterSetterProvider/SelectionView'
4+
5+
module.exports =
6+
7+
##*
8+
# Provides getter and setter (accessor and mutator) generation capabilities.
9+
##
10+
class GetterSetterProvider extends AbstractProvider
11+
###*
12+
* The view that allows the user to select the properties to generate for.
13+
###
14+
selectionView: null
15+
16+
###*
17+
* @inheritdoc
18+
###
19+
activate: (service) ->
20+
super(service)
21+
22+
@selectionView = new SelectionView(@onConfirm.bind(this), @onCancel.bind(this))
23+
24+
atom.commands.add 'atom-workspace', "php-integrator-refactoring:generate-getter": =>
25+
@executeCommand(true, false)
26+
27+
atom.commands.add 'atom-workspace', "php-integrator-refactoring:generate-setter": =>
28+
@executeCommand(false, true)
29+
30+
atom.commands.add 'atom-workspace', "php-integrator-refactoring:generate-getter-setter-pair": =>
31+
@executeCommand(true, true)
32+
33+
# TODO: The base menu should always be the same, add to base class.
34+
# TODO: The menu ordering is not ideal.
35+
# TODO: Add docblocks everywhere.
36+
37+
atom.menu.add([
38+
{
39+
'label': 'Packages'
40+
'submenu': [
41+
{
42+
'label': 'PHP Integrator',
43+
'submenu': [
44+
{
45+
'label': 'Refactoring'
46+
'submenu': [
47+
{'label': 'Generate Getter(s)', 'command': 'php-integrator-refactoring:generate-getter'},
48+
{'label': 'Generate Setter(s)', 'command': 'php-integrator-refactoring:generate-setter'},
49+
{'label': 'Generate Getter And Setter Pair(s)', 'command': 'php-integrator-refactoring:generate-getter-setter-pair'},
50+
]
51+
}
52+
]
53+
}
54+
]
55+
}
56+
])
57+
58+
executeCommand: (enableGetterGeneration, enableSetterGeneration) ->
59+
activeTextEditor = atom.workspace.getActiveTextEditor()
60+
61+
return if not activeTextEditor
62+
63+
@selectionView.storeFocusedElement()
64+
@selectionView.present()
65+
66+
currentClassName = @service.determineFullClassName(activeTextEditor)
67+
68+
@service.getClassInfo(currentClassName, true).then (classInfo) =>
69+
items = []
70+
71+
for name, property of classInfo.properties
72+
isClassType = false
73+
enablePhp7Features = false
74+
75+
# TODO: Fill in enableTypeHintGeneration based on if it's a class type or not. If enablePhp7Features
76+
# is true, this can always be true.
77+
78+
items.push({
79+
name : name
80+
type : if property.return.type then property.return.resolvedType else 'mixed'
81+
needsGetter : enableGetterGeneration
82+
needsSetter : enableSetterGeneration
83+
enablePhp7Features : enablePhp7Features
84+
enableTypeHintGeneration : enablePhp7Features or isClassType # NOTE: Not relevant for getters.
85+
editor : activeTextEditor
86+
})
87+
88+
@selectionView.setItems(items)
89+
90+
# TODO: We should actually be adding an 'unresolved' type. The 'type' is already partially resolved due
91+
# to the base package's NameResolver (node visitor).
92+
# TODO: Class properties that already have a getter/setter should be crossed out (strikethrough).
93+
# TODO: Support multiple items with check marks, like git-plus' "Stage Files" view.
94+
95+
###*
96+
* @inheritdoc
97+
###
98+
deactivate: () ->
99+
@selectionView.destroy()
100+
101+
# TODO: Remove commands and menu items again?
102+
103+
onCancel: () ->
104+
105+
106+
onConfirm: (item) ->
107+
getter = ''
108+
109+
# TODO: Very silly, but Atom won't automatically maintain indentation, so we'll have to fetch the cursor's
110+
# column and insert that many spaces to every line...
111+
112+
# TODO: Only generate type hints for class properties (optionally add a checkbox to the selection view
113+
# to specify whether the user wants type hints for basic types as well if he using PHP 7).
114+
115+
if item.needsGetter
116+
returnTypeDeclaration = ''
117+
118+
if item.enablePhp7Features
119+
returnTypeDeclaration = ': ' + item.type
120+
121+
getterName = 'get' + item.name.substr(0, 1).toUpperCase() + item.name.substr(1)
122+
123+
getter = """
124+
/**
125+
* Retrieves the currently set #{item.name}.
126+
*
127+
* @return #{item.type}
128+
*/
129+
public function #{getterName}()#{returnTypeDeclaration}
130+
{
131+
return $this->#{item.name};
132+
}
133+
"""
134+
135+
setter = ''
136+
137+
if item.needsSetter
138+
typePrefix = ''
139+
140+
if item.enableTypeHintGeneration
141+
typePrefix = item.type + ' '
142+
143+
returnTypeDeclaration = ''
144+
145+
if item.enablePhp7Features
146+
returnTypeDeclaration = ': self'
147+
148+
setterName = 'set' + item.name.substr(0, 1).toUpperCase() + item.name.substr(1)
149+
150+
setter = """
151+
/**
152+
* Sets the #{item.name} to use.
153+
*
154+
* @param #{item.type} $value
155+
*
156+
* @return $this
157+
*/
158+
public function #{setterName}(#{typePrefix}$value)#{returnTypeDeclaration}
159+
{
160+
$this->#{item.name} = $value;
161+
return $this;
162+
}
163+
"""
164+
165+
item.editor.insertText((getter + "\n\n" + setter).trim())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{SelectListView} = require 'atom-space-pen-views'
2+
3+
module.exports =
4+
5+
##*
6+
# The view that allows the user to select the properties to generate for.
7+
##
8+
class SelectionView extends SelectListView
9+
onDidConfirm: null
10+
onDidCancel: null
11+
12+
constructor: (@onDidConfirm, @onDidCancel = null) ->
13+
super()
14+
15+
initialize: ->
16+
super()
17+
18+
@addClass('overlay from-top')
19+
@panel ?= atom.workspace.addModalPanel(item: this, visible: false)
20+
21+
# @panel.destroy()
22+
23+
viewForItem: (item) ->
24+
"<li>#{item.name}</li>"
25+
26+
getFilterKey: () ->
27+
return 'name'
28+
29+
confirmed: (item) ->
30+
if @onDidConfirm
31+
@onDidConfirm(item)
32+
33+
@restoreFocus()
34+
@panel.hide()
35+
36+
cancelled: () ->
37+
if @onDidCancel
38+
@onDidCancel()
39+
40+
@restoreFocus()
41+
@panel.hide()
42+
43+
present: () ->
44+
@panel.show()
45+
@focusFilterEditor()

lib/Main.coffee

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
module.exports =
2+
###*
3+
* List of refactoring 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+
GetterSetterProvider = require './GetterSetterProvider'
23+
24+
@providers = []
25+
@providers.push new GetterSetterProvider()
26+
27+
for provider in @providers
28+
provider.activate(service)
29+
30+
###*
31+
* Deactivates any active providers.
32+
###
33+
deactivateProviders: () ->
34+
for provider in @providers
35+
provider.deactivate()
36+
37+
@providers = []
38+
39+
###*
40+
* Sets the php-integrator service.
41+
*
42+
* @param {mixed} service
43+
###
44+
setService: (service) ->
45+
@activateProviders(service)
46+
47+
{Disposable} = require 'atom'
48+
49+
return new Disposable => @deactivateProviders()

0 commit comments

Comments
 (0)