diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml
index 69dbd2232664..80ca13f10417 100644
--- a/plugins/groovy/src/META-INF/plugin.xml
+++ b/plugins/groovy/src/META-INF/plugin.xml
@@ -360,6 +360,8 @@
+
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandler.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandler.kt
new file mode 100644
index 000000000000..3a9c68b1a6f5
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandler.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.groovy.codeInsight.editorActions
+
+import com.intellij.codeInsight.editorActions.moveLeftRight.MoveElementLeftRightHandler
+import com.intellij.psi.PsiElement
+import com.intellij.psi.util.PsiTreeUtil.getChildrenOfAnyType
+import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap
+import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList
+import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationArgumentList
+import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationArrayInitializer
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrEnumTypeDefinition
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrReferenceList
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList
+import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameterList
+
+class GroovyMoveLeftRightHandler : MoveElementLeftRightHandler() {
+
+ override fun getMovableSubElements(element: PsiElement): Array = when (element) {
+ is GrAnnotationArgumentList -> element.attributes
+ is GrAnnotationArrayInitializer -> element.initializers
+ is GrArgumentList -> element.allArguments
+ is GrEnumTypeDefinition -> element.enumConstants
+ is GrListOrMap -> getChildrenOfAnyType(element, GrExpression::class.java, GrNamedArgument::class.java).toTypedArray()
+ is GrModifierList -> element.modifiers
+ is GrParameterList -> element.parameters
+ is GrReferenceList -> element.referenceElementsGroovy
+ is GrTypeArgumentList -> element.typeArgumentElements
+ is GrTypeParameterList -> element.typeParameters
+ is GrVariableDeclaration -> element.variables
+ else -> PsiElement.EMPTY_ARRAY
+ }
+}
\ No newline at end of file
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandlerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandlerTest.groovy
new file mode 100644
index 000000000000..853776de8f59
--- /dev/null
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInsight/editorActions/GroovyMoveLeftRightHandlerTest.groovy
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.groovy.codeInsight.editorActions
+
+import com.intellij.openapi.actionSystem.IdeActions
+import com.intellij.testFramework.LightProjectDescriptor
+import groovy.transform.CompileStatic
+import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor
+import org.jetbrains.plugins.groovy.LightGroovyTestCase
+
+@CompileStatic
+class GroovyMoveLeftRightHandlerTest extends LightGroovyTestCase {
+
+ final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST
+
+ private void doTest(String before, String after = null) {
+ fixture.with {
+ configureByText '_.groovy', before
+ performEditorAction(IdeActions.MOVE_ELEMENT_RIGHT)
+ if (after != null) {
+ checkResult after
+ performEditorAction(IdeActions.MOVE_ELEMENT_LEFT)
+ }
+ checkResult before
+ }
+ }
+
+ void 'test annotation argument'() {
+ doTest '@MyAnno(a = "e", b = "f") def a',
+ '@MyAnno(b = "f", a = "e") def a'
+ doTest '@MyAnno(a = "e", b = "f") def a'
+ }
+
+ void 'test annotation array initializer'() {
+ doTest '@MyAnno([1, 2, 3])',
+ '@MyAnno([2, 1, 3])'
+ doTest '@MyAnno(a = [1, 2, 3], b = 2)'
+ }
+
+ void 'test argument list'() {
+ doTest 'def foo(def...a) {}; foo(1, 2, 3)',
+ 'def foo(def...a) {}; foo(1, 3, 2)'
+ doTest 'def foo(def...a) {}; foo(1, a: 2, 3)',
+ 'def foo(def...a) {}; foo(1, 3, a: 2)'
+ }
+
+ void 'test enum definition'() {
+ doTest 'enum E {ONE, TWO, THREE}',
+ 'enum E {ONE, THREE, TWO}'
+ doTest 'enum E {ONE, TWO, THREE}'
+ }
+
+ void 'test list or map'() {
+ doTest '[1, 2, 3]',
+ '[2, 1, 3]'
+ doTest '[a: 1, b: 2, c: 3]',
+ '[b: 2, a: 1, c: 3]'
+ doTest '[1, a: 2, 3]',
+ '[a: 2, 1, 3]'
+ }
+
+ void 'test method modifier list'() {
+ doTest 'synchronized @Deprecated def foo() {}',
+ '@Deprecated synchronized def foo() {}'
+ doTest 'synchronized @Deprecated def foo() {}'
+ }
+
+ void 'test class modifier list'() {
+ doTest 'public @Deprecated class A {}',
+ '@Deprecated public class A {}'
+ doTest 'public @Deprecated class A {}'
+ }
+
+ void 'test parameter list'() {
+ doTest 'def foo(a, b = 2, c){}',
+ 'def foo(b = 2, a, c){}'
+ doTest 'def foo(a, b = 2, c){}'
+ }
+
+ void 'test implements list'() {
+ doTest 'class A implements Foo, Bar, Baz {}',
+ 'class A implements Bar, Foo, Baz {}'
+ doTest 'class A implements Foo, Bar, Baz {}'
+ }
+
+ void 'test extends list'() {
+ doTest 'class B extends Foo, Bar, Baz {}',
+ 'class B extends Bar, Foo, Baz {}'
+ doTest 'class B extends Foo, Bar, Baz {}'
+ }
+
+ void 'test throws list'() {
+ doTest 'def foo() throws Foo, Bar, Baz {}',
+ 'def foo() throws Bar, Foo, Baz {}'
+ doTest 'def foo() throws Foo, Bar, Baz {}'
+ }
+
+ void 'test type parameter list'() {
+ doTest 'class A<T, U, K> {}',
+ 'class AT, K> {}'
+ doTest 'class AK> {}'
+ }
+
+ void 'test type argument list'() {
+ doTest 'new A<K,V>', 'new AK>'
+ doTest 'new AV>'
+ }
+
+ void 'test variable declaration'() {
+ doTest 'def a = 1, b = 2, c', 'def a = 1, c, b = 2'
+ doTest 'def a = 1, b = 2, c'
+ }
+
+ void 'test binary expression'() {
+ doTest '1 + 2 + 3'
+ doTest '1 + 2 + 3'
+ }
+}