Bug 8519 - keystroke macros recording and playing capability
Change-Id: Iaad9fa7a3e6c54b15cf814a38f83aea131368731
Signed-off-by: Fabio Zadrozny <fabiofz@gmail.com>
diff --git a/build/org.eclipse.e4.ui.update/category.xml b/build/org.eclipse.e4.ui.update/category.xml
index 0503a14..10737ae 100644
--- a/build/org.eclipse.e4.ui.update/category.xml
+++ b/build/org.eclipse.e4.ui.update/category.xml
@@ -12,12 +12,9 @@
<feature id="org.eclipse.ui.glance.feature" version="0.0.1.qualifier">
<category name="Incrementation Text Search with Eclipse Glance"/>
</feature>
- <bundle id="org.eclipse.e4.ui.macros" version="0.1.0.qualifier">
+ <feature id="org.eclipse.e4.ui.macros.feature" version="0.1.0.qualifier">
<category name="Macros"/>
- </bundle>
- <bundle id="org.eclipse.e4.ui.macros.jdt" version="0.1.0.qualifier">
- <category name="Macros"/>
- </bundle>
+ </feature>
<bundle id="org.eclipse.e4.jdt.scope" version="0.0.1.qualifier">
<category name="JDT"/>
</bundle>
@@ -25,7 +22,11 @@
<category name="Misc"/>
</bundle>
<category-def name="org.eclipse.e4.ui.keys" label="Eclipse e4 Key Schemes"/>
- <category-def name="Macros" label="Keyboard macros"/>
+ <category-def name="Macros" label="Keyboard macros">
+ <description>
+ Record/playback
+ </description>
+ </category-def>
<category-def name="JDT" label="JDT/PDE Extensions"/>
<category-def name="Misc" label="Misc"/>
<category-def name="Incrementation Text Search with Eclipse Glance" label="Incrementation Text Search with Eclipse Glance">
diff --git a/bundles/.project b/bundles/.project
new file mode 100644
index 0000000..38d4784
--- /dev/null
+++ b/bundles/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>bundles</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.e4.core.macros/.classpath b/bundles/org.eclipse.e4.core.macros/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/.project b/bundles/org.eclipse.e4.core.macros/.project
similarity index 64%
copy from bundles/org.eclipse.e4.ui.macros.jdt/.project
copy to bundles/org.eclipse.e4.core.macros/.project
index 4babb46..a8f2e12 100644
--- a/bundles/org.eclipse.e4.ui.macros.jdt/.project
+++ b/bundles/org.eclipse.e4.core.macros/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>org.eclipse.e4.ui.macros.jdt</name>
+ <name>org.eclipse.e4.core.macros</name>
<comment></comment>
<projects>
</projects>
@@ -20,9 +20,20 @@
<arguments>
</arguments>
</buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
</natures>
</projectDescription>
diff --git a/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.core.runtime.prefs b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..fdfba91
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,421 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=error
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=error
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=error
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=error
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=error
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=120
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..2ecc6a3
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,73 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=org.eclipse.jdt.ui.default.eclipse_profile
+formatter_settings_version=12
+internal.default.compliance=user
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return Returns the ${bare_field_name}.\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} The ${bare_field_name} to set.\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment"/><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @since 3.5\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=true
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=false
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.pde.api.tools.prefs b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 0000000..a09ec9c
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,97 @@
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+API_USE_SCAN_FIELD_SEVERITY=Error
+API_USE_SCAN_METHOD_SEVERITY=Error
+API_USE_SCAN_TYPE_SEVERITY=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_JAVADOC_TAG=Warning
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Error
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+MISSING_EE_DESCRIPTIONS=Warning
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Warning
+automatically_removed_unused_problem_filters=false
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Error
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.pde.prefs b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.pde.prefs
new file mode 100644
index 0000000..be3cfc2
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/.settings/org.eclipse.pde.prefs
@@ -0,0 +1,35 @@
+compilers.f.unresolved-features=1
+compilers.f.unresolved-plugins=1
+compilers.incompatible-environment=1
+compilers.p.build=1
+compilers.p.build.bin.includes=1
+compilers.p.build.encodings=2
+compilers.p.build.java.compiler=2
+compilers.p.build.java.compliance=1
+compilers.p.build.missing.output=2
+compilers.p.build.output.library=1
+compilers.p.build.source.library=1
+compilers.p.build.src.includes=1
+compilers.p.deprecated=0
+compilers.p.discouraged-class=1
+compilers.p.illegal-att-value=0
+compilers.p.internal=1
+compilers.p.missing-packages=1
+compilers.p.missing-version-export-package=2
+compilers.p.missing-version-import-package=2
+compilers.p.missing-version-require-bundle=1
+compilers.p.no-required-att=0
+compilers.p.not-externalized-att=0
+compilers.p.unknown-attribute=0
+compilers.p.unknown-class=1
+compilers.p.unknown-element=1
+compilers.p.unknown-identifier=1
+compilers.p.unknown-resource=1
+compilers.p.unresolved-ex-points=0
+compilers.p.unresolved-import=0
+compilers.p.unused-element-or-attribute=1
+compilers.s.create-docs=false
+compilers.s.doc-folder=doc
+compilers.s.open-tags=1
+compilers.use-project=true
+eclipse.preferences.version=1
diff --git a/bundles/org.eclipse.e4.core.macros/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.core.macros/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5306d02
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/META-INF/MANIFEST.MF
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %Bundle-Name
+Bundle-SymbolicName: org.eclipse.e4.core.macros;singleton:=true
+Bundle-Version: 0.1.0.qualifier
+Bundle-Vendor: %Bundle-Vendor
+Require-Bundle: org.eclipse.osgi;bundle-version="3.11",
+ org.eclipse.e4.core.contexts;bundle-version="1.5",
+ org.eclipse.osgi.services;bundle-version="3.5",
+ org.eclipse.equinox.util;bundle-version="1.0",
+ org.eclipse.equinox.ds;bundle-version="1.4",
+ org.eclipse.e4.core.di;bundle-version="1.6",
+ org.eclipse.equinox.registry;bundle-version="3.6",
+ javax.inject;bundle-version="1.0",
+ org.eclipse.core.runtime;bundle-version="3.12",
+ org.eclipse.e4.ui.bindings;bundle-version="0.11"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.e4.core.macros.Activator
+Export-Package: org.eclipse.e4.core.macros,
+ org.eclipse.e4.core.macros.internal;x-friends:="org.eclipse.e4.ui.macros.tests,org.eclipse.e4.ui.macros,org.eclipse.ui.workbench.texteditor.macros"
+Service-Component: OSGI-INF/macroService.xml
diff --git a/bundles/org.eclipse.e4.core.macros/OSGI-INF/l10n/bundle.properties b/bundles/org.eclipse.e4.core.macros/OSGI-INF/l10n/bundle.properties
new file mode 100644
index 0000000..b53b6c4
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/OSGI-INF/l10n/bundle.properties
@@ -0,0 +1,6 @@
+#Properties file for org.eclipse.e4.core.macros
+Bundle-Name = Core Macro Recording and Playback
+Bundle-Vendor = Eclipse.org
+extension-point.macroInstructionsFactory.name = Register class to recreate a macro instruction which has been previously recorded through the macro record/playback engine.
+extension-point.macroStateListeners.name = Listeners for changes in the macro service (i.e.: record/playback mode).
+extension-point.macroCommandCustomization.name = Describe command ids which should have some customization in macro handling (by default commands have their activation automatically record an IMacroInstruction and this extension allows a different handling).
diff --git a/bundles/org.eclipse.e4.core.macros/OSGI-INF/macroService.xml b/bundles/org.eclipse.e4.core.macros/OSGI-INF/macroService.xml
new file mode 100644
index 0000000..634ccfa
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/OSGI-INF/macroService.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.e4.core.macros.macroService">
+ <implementation class="org.eclipse.e4.core.macros.internal.MacroServiceCreationFunction"/>
+ <service>
+ <provide interface="org.eclipse.e4.core.contexts.IContextFunction"/>
+ </service>
+ <property name="service.context.key" type="String" value="org.eclipse.e4.core.macros.EMacroService"/>
+</scr:component>
diff --git a/bundles/org.eclipse.e4.core.macros/build.properties b/bundles/org.eclipse.e4.core.macros/build.properties
new file mode 100644
index 0000000..63c8f29
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/build.properties
@@ -0,0 +1,17 @@
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ schema/,\
+ OSGI-INF/
+source.. = src/
+src.includes = schema/,\
+ src/,\
+ plugin.xml,\
+ pom.xml,\
+ build.properties,\
+ OSGI-INF/,\
+ META-INF/,\
+ .project,\
+ .classpath,\
+ .settings/
diff --git a/bundles/org.eclipse.e4.core.macros/plugin.xml b/bundles/org.eclipse.e4.core.macros/plugin.xml
new file mode 100644
index 0000000..8a78a5f
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/plugin.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension-point id="macroInstructionsFactory" name="%extension-point.macroInstructionsFactory.name" schema="schema/macroInstructionsFactory.exsd"/>
+ <extension-point id="macroStateListeners" name="%extension-point.macroStateListeners.name" schema="schema/macroStateListeners.exsd"/>
+ <extension-point id="macroCommandCustomization" name="%extension-point.macroCommandCustomization.name" schema="schema/macroCommandCustomization.exsd"/>
+</plugin>
diff --git a/bundles/org.eclipse.e4.core.macros/pom.xml b/bundles/org.eclipse.e4.core.macros/pom.xml
new file mode 100644
index 0000000..761f23f
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2017 Fabio Zadrozny and others.
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Distribution License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/org/documents/edl-v10.php
+
+ Contributors:
+ Fabio Zadrozny - initial implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.e4.ui</groupId>
+ <artifactId>e4-ui-aggregator</artifactId>
+ <version>0.17.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+
+ <artifactId>org.eclipse.e4.core.macros</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+
+ </project>
diff --git a/bundles/org.eclipse.e4.core.macros/schema/macroCommandCustomization.exsd b/bundles/org.eclipse.e4.core.macros/schema/macroCommandCustomization.exsd
new file mode 100644
index 0000000..b5df3f1
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/schema/macroCommandCustomization.exsd
@@ -0,0 +1,111 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.e4.ui.macros" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.e4.ui.macros" id="macroCommandCustomization" name=""/>
+ </appinfo>
+ <documentation>
+ Defines commands that will be customized during a macro record/playback operation -- by default,
+a macro instruction should be automatically added when in macro record mode to execute Eclipse commands
+during playback and this extension allows customization over that (i.e.: to skip recording a command).
+
+It's also possible to programatically customize how Eclipse commands are handled through the org.eclipse.e4.core.macros.EMacroService.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <choice minOccurs="1" maxOccurs="unbounded">
+ <element ref="whitelistedCommand"/>
+ </choice>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="whitelistedCommand">
+ <annotation>
+ <documentation>
+ A command which is allowed during macro record/playback.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ A command identifier
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.ui.commands/command/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="recordMacroInstruction" type="boolean" use="required">
+ <annotation>
+ <documentation>
+ If true, the activation of the command will be recorded in the macro (i.e.: an IMacroInstruction will be automatically created and added to the macro when in record mode) and if false it won't.
+
+Examples of actions whose activation should be recorded include copy, paste, delete line and anything whose playback is simply re-executing that action.
+
+Examples of actions whose activation should not be recorded (in which case, they're allowed to execute, but only its side-effect should be recorded) include open find dialog (it should not open the dialog, just record the find text or replace text later on) and code-completion (code-completion may be allowed, but only the actual apply of a given code-completion should be recorded -- although the editor itself may decide to disable code-completion at its level so that the action does nothing until its code-completions aren't actually recorded in the macro).
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 0.1.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+
+<extension point="org.eclipse.e4.core.macros.macroCommandCustomization">
+ <customizedCommand id="org.eclipse.ui.edit.text.contentAssist.proposals" recordMacroInstruction="false"/>
+</extension>
+
+Will let the command "org.eclipse.ui.edit.text.contentAssist.proposals" be executed but will not record it to be re-executed on macro playback (in which case the command is responsible for recording its side-effects in the macro later on).
+ </documentation>
+ </annotation>
+
+
+
+
+</schema>
diff --git a/bundles/org.eclipse.e4.core.macros/schema/macroInstructionsFactory.exsd b/bundles/org.eclipse.e4.core.macros/schema/macroInstructionsFactory.exsd
new file mode 100644
index 0000000..b97365e
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/schema/macroInstructionsFactory.exsd
@@ -0,0 +1,108 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.e4.core.macros" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.e4.core.macros" id="macroInstructionsFactory" name="Factory for macro instructions"/>
+ </appinfo>
+ <documentation>
+ Register a factory for macro instructions (which is able to recreate an IMacroInstruction from the contents of its toMap() function).
+
+Any macro instruction which is added to the macro engine during the record phase must have a factory registered through this extension point (an error will be thrown if that's not the case).
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <choice minOccurs="1" maxOccurs="unbounded">
+ <element ref="macroInstructionsFactory"/>
+ </choice>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="macroInstructionsFactory">
+ <annotation>
+ <documentation>
+ A macro instruction factory, which is used to recreate a macro previously persisted during a macro record session (in order to properly play it back later on).
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="macroInstructionId" type="string" use="required">
+ <annotation>
+ <documentation>
+ The id of the macro instruction which this factory can be used to create (i.e.: the method org.eclipse.e4.core.macros.IMacroInstruction.getId(), of the macro instructions created by this factory must return the same id).
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ The class which is the factory to recreate macro instructions.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.e4.core.macros.IMacroInstructionFactory"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 0.1.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ <extension point="org.eclipse.e4.core.macros.macroInstructionsFactory">
+ <macroInstructionsFactory
+ class="org.eclipse.my.IMacroInstructionFactoryImplementation"
+ macroInstructionId="org.eclipse.my.macro.instructionId">
+ </macroInstructionsFactory>
+</extension>
+ </documentation>
+ </annotation>
+
+
+
+
+</schema>
diff --git a/bundles/org.eclipse.e4.core.macros/schema/macroStateListeners.exsd b/bundles/org.eclipse.e4.core.macros/schema/macroStateListeners.exsd
new file mode 100644
index 0000000..644404d
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/schema/macroStateListeners.exsd
@@ -0,0 +1,100 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.e4.core.macros" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.e4.core.macros" id="macroStateListeners" name="Listeners for changes on the macro state"/>
+ </appinfo>
+ <documentation>
+ Allows for other plugins to register listeners which must be notified of changes in the macro service (i.e.: when a record or playback is started or stopped).
+
+It's possible, for instance, to add listeners which will do the recording of keystrokes for playing back later when that happens, disable commands/actions which are not allowed during macro record/playback, add a listener to record changes to preferences, etc.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <choice minOccurs="1" maxOccurs="unbounded">
+ <element ref="macroStateListener"/>
+ </choice>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="macroStateListener">
+ <complexType>
+ <attribute name="class" type="string">
+ <annotation>
+ <documentation>
+ A listener for changes in the macro state (i.e.: macro record or playback started or stopped).
+
+Listeners should be added to listen the macro state when in order to properly record or playback a macro, some pre/post work must be done.
+
+For instance, an interceptor is added to the keybindings dispatcher in order to blacklist/whitelist commands being triggered by the user when in record mode.
+
+Note: it's lazily created the first time the macro service changes and the same instance is kept alive afterwards.
+
+Note: it's also possible to programatically add an IMacroStateListener to the EMacroService (so, existing instances, such as the text editor can act upon starting a macro record session and start recording keystrokes or disable code-completion if it can't deal with playing it back).
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.e4.core.macros.IMacroStateListener"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 0.1.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ <extension point="org.eclipse.e4.core.macros.macroStateListeners">
+ <macroStateListener
+ class="org.eclipse.impl.MyIMacroStateListenerImpl">
+ </macroStateListener>
+</extension>
+ </documentation>
+ </annotation>
+
+
+
+
+</schema>
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/Activator.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/Activator.java
new file mode 100644
index 0000000..ca98f0f
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/Activator.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Plugin activator.
+ */
+public class Activator extends Plugin {
+
+ private static Activator plugin;
+
+ public Activator() {
+ super();
+ plugin = this;
+ }
+
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ public static void log(Throwable exception) {
+ try {
+ if (plugin != null) {
+ plugin.getLog().log(new Status(IStatus.ERROR, plugin.getBundle().getSymbolicName(),
+ exception.getMessage(), exception));
+ } else {
+ // The plugin is not available. Just print to stderr.
+ exception.printStackTrace();
+ }
+ } catch (Exception e) {
+ // Print the original error if something happened, not the one
+ // related to the log not working.
+ exception.printStackTrace();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/CancelMacroException.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/CancelMacroException.java
new file mode 100644
index 0000000..f5afff7
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/CancelMacroException.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+public class CancelMacroException extends Exception {
+
+ private static final long serialVersionUID = -7828623675170028608L;
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/CancelMacroPlaybackException.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/CancelMacroPlaybackException.java
new file mode 100644
index 0000000..0cd7512
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/CancelMacroPlaybackException.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+/**
+ * An exception to be thrown when the macro playback should be stopped.
+ */
+public class CancelMacroPlaybackException extends CancelMacroException {
+
+ private static final long serialVersionUID = -953668757199552819L;
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/CancelMacroRecordingException.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/CancelMacroRecordingException.java
new file mode 100644
index 0000000..6ad6cd6
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/CancelMacroRecordingException.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+/**
+ * An exception to be thrown when the macro recording should be stopped.
+ */
+public class CancelMacroRecordingException extends CancelMacroException {
+
+ /**
+ * Generated serial version UID.
+ */
+ private static final long serialVersionUID = -5295116910722117940L;
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/EMacroService.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/EMacroService.java
new file mode 100644
index 0000000..3097995
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/EMacroService.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+/**
+ * Extension with the public API for dealing with macros.
+ *
+ * Can be accessed by getting it as a service:
+ * <p>
+ * site.getService(EMacroService.class)
+ * </p>
+ * or by having it injected:
+ * <p>
+ * @Inject<br/>
+ * EMacroService fMacroService;
+ * </p>
+ * <p>
+ * The idea is that clients will become aware that a macro record is taking
+ * place (through {@link #isRecording()} and will add their related macro
+ * instructions through {@link #addMacroInstruction(IMacroInstruction)}.
+ * </p>
+ * <p>
+ * It's also important to note that any macro instruction added through
+ * addMacroInstruction also needs to have an {@link IMacroInstructionFactory}
+ * registered through the org.eclipse.e4.core.macros.macroInstructionsFactory
+ * extension point (with a match through
+ * {@link org.eclipse.e4.core.macros.IMacroInstruction#getId()}).
+ * </p>
+ */
+public interface EMacroService {
+
+ /**
+ * @return whether a macro is currently being recorded (note that it's possible
+ * for the user to start recording and then playback a macro
+ * simultaneously -- although the inverse is not true).
+ */
+ boolean isRecording();
+
+ /**
+ * @return whether a macro is currently being played back.
+ */
+ boolean isPlayingBack();
+
+ /**
+ * Adds a macro instruction to be added to the current macro being recorded. Any
+ * macro instruction added also needs to have an
+ * {@link IMacroInstructionFactory} registered through the
+ * org.eclipse.e4.core.macros.macroInstructionsFactory extension point (with a
+ * match through {@link org.eclipse.e4.core.macros.IMacroInstruction#getId()})
+ *
+ * Does nothing if there's no macro being currently recorded.
+ *
+ * @param macroInstruction
+ * the macro instruction to be added to the macro currently being
+ * recorded.
+ */
+ void addMacroInstruction(IMacroInstruction macroInstruction);
+
+ int PRIORITY_LOW = 0;
+
+ int PRIORITY_HIGH = 10;
+
+ /**
+ * Adds a macro instruction to be added to the current macro being recorded. The
+ * difference between this method and
+ * {@link #addMacroInstruction(IMacroInstruction)} is that it's meant to be used
+ * when an event may trigger the creation of multiple macro instructions and
+ * only one of those should be recorded.
+ *
+ * For instance, if a given KeyDown event is recorded in a StyledText and later
+ * an action is triggered by this event, the recorded action should overwrite
+ * the KeyDown event.
+ *
+ * @param macroInstruction
+ * the macro instruction to be added to the macro currently being
+ * recorded.
+ * @param event
+ * the event that triggered the creation of the macro instruction to
+ * be added. If there are multiple macro instructions added for the
+ * same event, only the one with the highest priority will be kept
+ * (if 2 events have the same priority, the last one will replace the
+ * previous one).
+ * @param priority
+ * the priority of the macro instruction being added (to be compared
+ * against the priority of other added macro instructions for the
+ * same event).
+ * @see #addMacroInstruction(IMacroInstruction)
+ */
+ void addMacroInstruction(IMacroInstruction macroInstruction, Object event, int priority);
+
+ /**
+ * Toggles the macro record mode (i.e.: if it's currently not recording, starts
+ * recording a macro, otherwise, stops the current record -- at which point a
+ * macro should be saved with what was recorded so far).
+ *
+ * Note that when playing back, calling toggleMacroRecord() should do nothing
+ * (while it's Ok to start recording and then playback a previous macro to add
+ * previously recorded macro instructions to the current macro, the opposite is
+ * not true).
+ */
+ void toggleMacroRecord();
+
+ /**
+ * Plays back the last recorded macro.
+ *
+ * Note: it's Ok to call it while a macro is being recorded (which should
+ * playback the given macro and add its contents to the new macro being
+ * recorded).
+ *
+ * @throws MacroPlaybackException
+ */
+ void playbackLastMacro() throws MacroPlaybackException;
+
+ /**
+ * Adds a macro state listener to be notified on changes in the macro
+ * record/playback state.
+ *
+ * @param listener
+ * the listener to be added.
+ */
+ void addMacroStateListener(IMacroStateListener listener);
+
+ /**
+ * @param listener
+ * the macro listener which should no longer be notified of changes.
+ */
+ void removeMacroStateListener(IMacroStateListener listener);
+
+ /**
+ * @return the macro record context created when macro record started or null if
+ * it's not currently recording.
+ */
+ IMacroRecordContext getMacroRecordContext();
+
+ /**
+ * @return the macro playback context created when the macro playback started or
+ * null if it's not currently playing back.
+ */
+ IMacroPlaybackContext getMacroPlaybackContext();
+
+ // Deal with managing accepted commands during macro record/playback.
+ // (by default should load the command behavior
+ // through the org.eclipse.e4.core.macros.macroCommandCustomization extension
+ // point,
+ // but it's possible to programmatically change it as needed later on).
+
+ /**
+ * @param commandId
+ * the id of the command.
+ *
+ * @return whether the command should be recorded for playback when recording a
+ * macro (i.e.: an {@link org.eclipse.e4.core.macros.IMacroInstruction}
+ * will be automatically created to play it back when in record mode).
+ *
+ * @see org.eclipse.e4.core.macros.macroCommandCustomization extension point
+ */
+ @SuppressWarnings("javadoc")
+ boolean getRecordCommandInMacro(String commandId);
+
+ /**
+ * @param commandId
+ * the command id to be customized during macro record/playback.
+ *
+ * @param recordInMacro
+ * if true, the command activation will be automatically recorded in
+ * the macro -- which means that an
+ * {@link org.eclipse.e4.core.macros.IMacroInstruction} will be
+ * automatically created to play it back when in record mode. If
+ * false, the activation of the command will not be recorded.
+ *
+ * @see org.eclipse.e4.core.macros.macroCommandCustomization extension point
+ */
+ @SuppressWarnings("javadoc")
+ void setRecordCommandInMacro(String commandId, boolean recordInMacro);
+
+ /**
+ * Adds a macro instructions listener (it may be added to validate the current
+ * state of the macro recording).
+ *
+ * @param macroInstructionsListener
+ * the listener for macro instructions.
+ */
+ void addMacroInstructionsListener(IMacroInstructionsListener macroInstructionsListener);
+
+ /**
+ * Removes a macro instructions listener.
+ *
+ * @param macroInstructionsListener
+ * the listener for macro instructions.
+ */
+ void removeMacroInstructionsListener(IMacroInstructionsListener macroInstructionsListener);
+
+ /**
+ * @return the number of macro instructions in the macro currently recorded or
+ * -1 if no macro is being recorded.
+ */
+ int getLenOfMacroBeingRecorded();
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroContext.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroContext.java
new file mode 100644
index 0000000..4569588
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroContext.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+/**
+ * The context bound to the macro record or playback.
+ */
+public interface IMacroContext {
+
+ /**
+ * @param key
+ * the key of the variable to be retrieved.
+ * @return the object related to that variable.
+ */
+ public Object get(String key);
+
+ /**
+ * @param key
+ * the key of the variable to store.
+ * @param value
+ * the value to be stored for that key.
+ */
+ public void set(String key, Object value);
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroInstruction.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroInstruction.java
new file mode 100644
index 0000000..4a5b13f
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroInstruction.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+import java.util.Map;
+
+/**
+ * The basic abstraction of a macro instruction (i.e.: a macro may be composed
+ * of multiple macro instructions). The macro instruction also can be stored in
+ * disk to be reconstructed later on.
+ */
+public interface IMacroInstruction {
+
+ /**
+ * @return the id for the macro instruction.
+ * @note this id may be visible to the user, so, it should ideally be something
+ * short and readable (such as KeyDown, or Command), not a dotted name as
+ * is usual for Eclipse ids (and it can't be changed afterwards).
+ */
+ String getId();
+
+ /**
+ * Executes the macro instruction in the given context.
+ *
+ * @param macroPlaybackContext
+ * the context used to playback the macro.
+ * @throws MacroPlaybackException
+ * if something didn't work when executing the macro.
+ */
+ void execute(IMacroPlaybackContext macroPlaybackContext) throws MacroPlaybackException;
+
+ /**
+ * Convert the macro instruction into a map (which may be later dumped to the
+ * disk) and recreated with an
+ * {@link org.eclipse.e4.core.macros.IMacroInstructionFactory} registered
+ * through the org.eclipse.e4.core.macros.macroInstructionsFactory extension
+ * point.
+ *
+ * @return a map which may be dumped to the disk and can be used to recreate the
+ * macro instruction later on.
+ */
+ Map<String, String> toMap();
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroInstructionFactory.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroInstructionFactory.java
new file mode 100644
index 0000000..330c869
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroInstructionFactory.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+import java.util.Map;
+
+/**
+ * Factory for macro instructions which had the contents of
+ * {@link IMacroInstruction#toMap()} persisted.
+ *
+ * Should be registered through the
+ * org.eclipse.e4.core.macros.macroInstructionsFactory extension point (with a
+ * match through {@link org.eclipse.e4.core.macros.IMacroInstruction#getId()}).
+ */
+public interface IMacroInstructionFactory {
+
+ /**
+ * @param stringMap
+ * a map which was created from {@link IMacroInstruction#toMap()}
+ * @return the {@link IMacroInstruction} created from the given stringMap.
+ * @throws Exception
+ * if some error happened recreating the macro instruction.
+ */
+ IMacroInstruction create(Map<String, String> stringMap) throws Exception;
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroInstructionsListener.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroInstructionsListener.java
new file mode 100644
index 0000000..3d83d15
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroInstructionsListener.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+/**
+ * A listener for the macro instructions being added.
+ */
+public interface IMacroInstructionsListener {
+
+ /**
+ * The macro instruction to be added to the macro.
+ *
+ * @param macroInstruction
+ * the macro instruction to be added.
+ * @throws CancelMacroRecordingException
+ * if the recording of the macro should stop before actually adding
+ * the given macro instruction.
+ */
+ void beforeMacroInstructionAdded(IMacroInstruction macroInstruction) throws CancelMacroRecordingException;
+
+ /**
+ * Called after a given macro instruction is added to the macro. Note that it's
+ * possible that beforeMacroInstructionAdded is called and
+ * afterMacroInstructionAdded isn't if the macro instruction doesn't have enough
+ * priority.
+ *
+ * @param macroInstruction
+ * the macro instruction just added to the current macro.
+ */
+ void afterMacroInstructionAdded(IMacroInstruction macroInstruction);
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroPlaybackContext.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroPlaybackContext.java
new file mode 100644
index 0000000..de1d14e
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroPlaybackContext.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+import java.util.Map;
+
+/**
+ * Context passed when playing back a macro.
+ */
+public interface IMacroPlaybackContext extends IMacroContext {
+
+ /**
+ * Creates a macro instruction (for execution) given its id and the
+ * {@link IMacroInstruction#toMap()} contents gotten from a previously recorded
+ * instruction.
+ *
+ * @param macroInstructionId
+ * the id of the macro instruction to be created.
+ * @param stringMap
+ * the contents previously gotten from
+ * {@link IMacroInstruction#toMap()}.
+ * @return a macro instruction created from the given id and parameters.
+ * @throws Exception
+ * if some error was thrown when creating the macro instruction.
+ */
+ IMacroInstruction createMacroInstruction(String macroInstructionId, Map<String, String> stringMap) throws Exception;
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroRecordContext.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroRecordContext.java
new file mode 100644
index 0000000..b6a837e
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroRecordContext.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+/**
+ * A context created when macro record starts.
+ */
+public interface IMacroRecordContext extends IMacroContext {
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroStateListener.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroStateListener.java
new file mode 100644
index 0000000..5a7eb8f
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroStateListener.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+/**
+ * Listener for changes in the EMacroService.
+ */
+public interface IMacroStateListener {
+
+ public enum StateChange {
+ RECORD_STARTED, PLAYBACK_STARTED, RECORD_FINISHED, PLAYBACK_FINISHED,
+ }
+
+ /**
+ * Called when a record started/stopped or a playback started/stopped. Note that
+ * a macro may be played back under a record session (although the opposite is
+ * not true).
+ *
+ * @param macroService
+ * the macro service where the change happened.
+ * @param stateChange
+ * the state change which just took place.
+ * @throws CancelMacroException
+ * to stop the record or playback from happening.
+ */
+ public void macroStateChanged(EMacroService macroService, StateChange stateChange)
+ throws CancelMacroException;
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroStateListener1.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroStateListener1.java
new file mode 100644
index 0000000..31b4b7a
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/IMacroStateListener1.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+/**
+ * Provides a way for clients to be notified of the creation of macro contexts
+ * to fill it as needed.
+ */
+public interface IMacroStateListener1 extends IMacroStateListener {
+
+ /**
+ * Called after the creation of the macro playback context (before notifying
+ * about changes to the macro state or actual playback).
+ *
+ * @param context
+ * the context for the macro playback.
+ */
+ public void onMacroPlaybackContextCreated(IMacroPlaybackContext context);
+
+ /**
+ * Called after the creation of the macro record context (before notifying about
+ * changes to the macro state or actual record).
+ *
+ * @param context
+ * the context for the macro record.
+ */
+ public void onMacroRecordContextCreated(IMacroRecordContext context);
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/MacroPlaybackException.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/MacroPlaybackException.java
new file mode 100644
index 0000000..9911e09
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/MacroPlaybackException.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros;
+
+/**
+ * An exception to be raised if there's some issue when playing back macros.
+ */
+public class MacroPlaybackException extends Exception {
+
+ /**
+ * @param msg
+ * message for exception.
+ */
+ public MacroPlaybackException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * @param msg
+ * message for exception.
+ * @param e
+ * cause of exception.
+ */
+ public MacroPlaybackException(String msg, Exception e) {
+ super(msg, e);
+ }
+
+ /**
+ * Generated serial version UID.
+ */
+ private static final long serialVersionUID = -2589166244366784288L;
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/ComposableMacro.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/ComposableMacro.java
new file mode 100644
index 0000000..806af4f
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/ComposableMacro.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros.internal;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.e4.core.macros.Activator;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroInstructionFactory;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.MacroPlaybackException;
+
+/**
+ * This is a macro which is created from a sequence of instructions which are
+ * stored in-memory (and may be persisted later on).
+ */
+/* default */ class ComposableMacro implements IMacro {
+
+ /**
+ * Provides the macro instruction id to an implementation which is able to
+ * recreate it.
+ */
+ private Map<String, IMacroInstructionFactory> fMacroInstructionIdToFactory;
+
+ /**
+ * The macro instructions which compose this macro.
+ */
+ private List<IMacroInstruction> fMacroInstructions = new ArrayList<>();
+
+ private static class IndexAndPriority {
+
+ private final int fIndex;
+ private final int fPriority;
+
+ private IndexAndPriority(int index, int priority) {
+ this.fIndex = index;
+ this.fPriority = priority;
+ }
+
+ }
+
+ /**
+ * Map of an event to the current index of the macro instruction in
+ * fMacroInstructions and the priority for the given macro instruction.
+ */
+ private final Map<Object, IndexAndPriority> fEventToPlacement = new HashMap<>();
+
+ /**
+ * @param macroInstructionIdToFactory
+ * Only macros instructions which have ids available as keys in the
+ * macroInstructionIdToFactory will be accepted.
+ */
+ public ComposableMacro(Map<String, IMacroInstructionFactory> macroInstructionIdToFactory) {
+ fMacroInstructionIdToFactory = macroInstructionIdToFactory;
+ }
+
+ /**
+ * Checks whether the added macro instruction is suitable to be added to this
+ * macro.
+ *
+ * @param macroInstruction
+ * the macro instruction to be checked.
+ */
+ private void checkMacroInstruction(IMacroInstruction macroInstruction) {
+ if (fMacroInstructionIdToFactory != null
+ && !fMacroInstructionIdToFactory.containsKey(macroInstruction.getId())) {
+ throw new RuntimeException(String.format(
+ "Macro instruction: %s not properly registered through a %s extension point.", //$NON-NLS-1$
+ macroInstruction.getId(), MacroServiceImplementation.MACRO_INSTRUCTION_FACTORY_EXTENSION_POINT));
+ }
+ }
+
+ /**
+ * Adds a new macro instruction to this macro.
+ *
+ * @param macroInstruction
+ * the macro instruction to be appended to this macro.
+ */
+ public void addMacroInstruction(IMacroInstruction macroInstruction) {
+ checkMacroInstruction(macroInstruction);
+ fMacroInstructions.add(macroInstruction);
+ }
+
+ /**
+ * Adds a macro instruction to be added to the current macro being recorded. The
+ * difference between this method and
+ * {@link #addMacroInstruction(IMacroInstruction)} is that it's meant to be used
+ * when an event may trigger the creation of multiple macro instructions and
+ * only one of those should be recorded.
+ *
+ * @param macroInstruction
+ * the macro instruction to be added to the macro currently being
+ * recorded.
+ * @param event
+ * the event that triggered the creation of the macro instruction to
+ * be added. If there are multiple macro instructions added for the
+ * same event, only the one with the highest priority will be kept
+ * (if 2 events have the same priority, the last one will replace the
+ * previous one).
+ * @param priority
+ * the priority of the macro instruction being added (to be compared
+ * against the priority of other added macro instructions for the
+ * same event).
+ * @return true if the macro instruction was actually added and false otherwise.
+ * @see #addMacroInstruction(IMacroInstruction)
+ */
+ public boolean addMacroInstruction(IMacroInstruction macroInstruction, Object event, int priority) {
+ Assert.isNotNull(event);
+ IndexAndPriority currentIndexAndPriority = this.fEventToPlacement.get(event);
+ if (currentIndexAndPriority == null) {
+ this.addMacroInstruction(macroInstruction);
+ this.fEventToPlacement.put(event, new IndexAndPriority(this.fMacroInstructions.size() - 1, priority));
+ return true;
+ }
+ if (priority >= currentIndexAndPriority.fPriority) {
+ checkMacroInstruction(macroInstruction);
+ fMacroInstructions.set(currentIndexAndPriority.fIndex, macroInstruction);
+ this.fEventToPlacement.put(event, new IndexAndPriority(currentIndexAndPriority.fIndex, priority));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Clears information obtained during recording which should be no longer needed
+ * after the macro is properly composed.
+ */
+ public void clearCachedInfo() {
+ this.fEventToPlacement.clear();
+ }
+
+ @Override
+ public void playback(IMacroPlaybackContext macroPlaybackContext) throws MacroPlaybackException {
+ for (IMacroInstruction macroInstruction : fMacroInstructions) {
+ macroInstruction.execute(macroPlaybackContext);
+ }
+ }
+
+ /**
+ * Actually returns the bytes to be written to the disk to be loaded back later
+ * on (the actual load and playback is later done by {@link SavedJSMacro}.
+ *
+ * @return an UTF-8 encoded array of bytes which can be used to rerun the macro
+ * later on.
+ */
+ /* default */ byte[] toJSBytes() {
+ final StringBuilder buf = new StringBuilder(this.fMacroInstructions.size() * 60);
+
+ buf.append("// Macro generated by the Eclipse macro record engine.\n"); //$NON-NLS-1$
+ buf.append("// The runMacro() function will be later run by the macro engine.\n"); //$NON-NLS-1$
+ buf.append("function runMacro(){\n"); //$NON-NLS-1$
+
+ for (IMacroInstruction macroInstruction : this.fMacroInstructions) {
+ Map<String, String> map = macroInstruction.toMap();
+ Assert.isNotNull(map);
+
+ buf.append(" runMacroInstruction("); //$NON-NLS-1$
+ buf.append(JSONHelper.quote(macroInstruction.getId()));
+ buf.append(", "); //$NON-NLS-1$
+ buf.append(JSONHelper.toJSon(map));
+ buf.append(");\n"); //$NON-NLS-1$
+ }
+ buf.append("}\n"); //$NON-NLS-1$
+
+ try {
+ return buf.toString().getBytes("UTF-8"); //$NON-NLS-1$
+ } catch (UnsupportedEncodingException e) {
+ // Make this a RuntimeException (UTF-8 should definitely be
+ // supported).
+ Activator.log(e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @return the number of macro instructions in this macro.
+ */
+ public int getLength() {
+ return this.fMacroInstructions.size();
+ }
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/IMacro.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/IMacro.java
new file mode 100644
index 0000000..22059ad
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/IMacro.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros.internal;
+
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.MacroPlaybackException;
+
+/**
+ * Basic interface for a macro (private API, only meant to be used inside the
+ * org.eclipse.e4.core.macros plugin).
+ *
+ * Note that the actual macro implementation could be created from a list of
+ * macro instructions in memory, a javascript file to be run, a json/xml
+ * describing macro commands, etc.
+ */
+/* default */ interface IMacro {
+
+ /**
+ * Used to playback a macro in the given context.
+ *
+ * @param macroPlaybackContext
+ * the context to playback the macro.
+ * @throws MacroPlaybackException
+ * if there was some error running the macro.
+ */
+ void playback(IMacroPlaybackContext macroPlaybackContext) throws MacroPlaybackException;
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/JSONHelper.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/JSONHelper.java
new file mode 100644
index 0000000..aad7125
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/JSONHelper.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros.internal;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Helper to convert a map to a JSON without adding new dependencies.
+ */
+public class JSONHelper {
+
+ public static String quote(String string) {
+ int len = string.length();
+ if (len == 0) {
+ return "\"\""; //$NON-NLS-1$
+ }
+
+ StringBuilder sb = new StringBuilder(len + 4);
+ sb.append('"');
+
+ for (int i = 0; i < len; i += 1) {
+ char c = string.charAt(i);
+ switch (c) {
+ case '"':
+ case '\\':
+ case '/':
+ sb.append('\\');
+ sb.append(c);
+ break;
+
+ case '\b':
+ sb.append("\\b"); //$NON-NLS-1$
+ break;
+
+ case '\f':
+ sb.append("\\f"); //$NON-NLS-1$
+ break;
+
+ case '\n':
+ sb.append("\\n"); //$NON-NLS-1$
+ break;
+
+ case '\r':
+ sb.append("\\r"); //$NON-NLS-1$
+ break;
+
+ case '\t':
+ sb.append("\\t"); //$NON-NLS-1$
+ break;
+
+ default:
+ if (c < ' ') {
+ String t = "000" + Integer.toHexString(c); //$NON-NLS-1$
+ sb.append("\\u" + t.substring(t.length() - 4)); //$NON-NLS-1$
+ } else {
+ sb.append(c);
+ }
+ }
+ }
+ sb.append('"');
+ return sb.toString();
+ }
+
+ /**
+ * @param map
+ * a map to be converted to a json string.
+ * @return a json string with the contents of the passed map.
+ */
+ public static String toJSon(Map<String, String> map) {
+ Iterator<Entry<String, String>> iterator = map.entrySet().iterator();
+ final StringBuilder buf = new StringBuilder("{"); //$NON-NLS-1$
+
+ while (iterator.hasNext()) {
+ if (buf.length() > 1) {
+ buf.append(", "); //$NON-NLS-1$
+ }
+ Entry<String, String> entry = iterator.next();
+ buf.append(quote(entry.getKey()));
+ buf.append(": "); //$NON-NLS-1$
+ buf.append(quote(entry.getValue()));
+ }
+ buf.append('}');
+ return buf.toString();
+ }
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroManager.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroManager.java
new file mode 100644
index 0000000..728660c
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroManager.java
@@ -0,0 +1,542 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.e4.core.macros.Activator;
+import org.eclipse.e4.core.macros.CancelMacroException;
+import org.eclipse.e4.core.macros.CancelMacroRecordingException;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroInstructionFactory;
+import org.eclipse.e4.core.macros.IMacroInstructionsListener;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.IMacroRecordContext;
+import org.eclipse.e4.core.macros.IMacroStateListener;
+import org.eclipse.e4.core.macros.IMacroStateListener.StateChange;
+import org.eclipse.e4.core.macros.IMacroStateListener1;
+import org.eclipse.e4.core.macros.MacroPlaybackException;
+
+/**
+ * Macro manager (pure java, without any OSGI requirements).
+ */
+public class MacroManager {
+
+ private static final String JS_EXT = ".js"; //$NON-NLS-1$
+
+ private static final String TEMP_MACRO_PREFIX = "temp_macro_"; //$NON-NLS-1$
+
+ /**
+ * The max number of temporary macros to be kept (can't be lower than 1).
+ */
+ private int fMaxNumberOfTemporaryMacros = 5;
+
+ /**
+ * @param maxNumberOfTemporaryMacros
+ * The max number of temporary macros to be kept.
+ */
+ public void setMaxNumberOfTemporaryMacros(int maxNumberOfTemporaryMacros) {
+ Assert.isTrue(maxNumberOfTemporaryMacros >= 1);
+ this.fMaxNumberOfTemporaryMacros = maxNumberOfTemporaryMacros;
+ }
+
+ /**
+ * @return Returns the max number of temporary macros to be kept.
+ */
+ public int getMaxNumberOfTemporaryMacros() {
+ return fMaxNumberOfTemporaryMacros;
+ }
+
+ /**
+ * The directories where macros should be looked up. The first directory is the
+ * one where macros are persisted.
+ */
+ private File[] fMacrosDirectories;
+
+ /**
+ * Holds the macro currently being recorded (if we're in record mode). If not in
+ * record mode, should be null.
+ */
+ private ComposableMacro fMacroBeingRecorded;
+
+ /**
+ * Holds the last recorded or played back macro.
+ */
+ private IMacro fLastMacro;
+
+ /**
+ * Flag indicating whether we're playing back a macro.
+ */
+ private boolean fIsPlayingBack = false;
+
+ /**
+ * State to be used when recording macro.
+ */
+ private IMacroRecordContext fMacroRecordContext;
+
+ /**
+ * State to be used when playing back macro.
+ */
+ private IMacroPlaybackContext fMacroPlaybackContext;
+
+ /**
+ * Creates a manager for macros which will read macros from the given
+ * directories.
+ *
+ * @param macrosDirectories
+ * the directories where macros should be looked up. The first
+ * directory is the one where macros are persisted. If there are 2
+ * macros which would end up having the same name, the one in the
+ * directory that appears last is the one which is used.
+ */
+ public MacroManager(File... macrosDirectories) {
+ setMacrosDirectories(macrosDirectories);
+ }
+
+ /**
+ * @param macrosDirectories
+ * the directories where macros should be looked up. The first
+ * directory is the one where macros are persisted. If there are 2
+ * macros which would end up having the same name, the one in the
+ * directory that appears last is the one which is used.
+ */
+ public void setMacrosDirectories(File... macrosDirectories) {
+ Assert.isNotNull(macrosDirectories);
+ for (File file : macrosDirectories) {
+ Assert.isNotNull(file);
+ }
+ this.fMacrosDirectories = macrosDirectories;
+ reloadMacros();
+ }
+
+ /**
+ * @return whether a macro is currently being recorded.
+ */
+ public boolean isRecording() {
+ return fMacroBeingRecorded != null;
+ }
+
+ /**
+ * @return whether a macro is currently being played back.
+ */
+ public boolean isPlayingBack() {
+ return fIsPlayingBack;
+ }
+
+ /**
+ * Adds a macro instruction to the macro currently being recorded. Does nothing
+ * if no macro is being recorded.
+ *
+ * @param macroInstruction
+ * the macro instruction to be recorded.
+ * @throws CancelMacroRecordingException
+ */
+ public void addMacroInstruction(IMacroInstruction macroInstruction) throws CancelMacroRecordingException {
+ ComposableMacro macroBeingRecorded = fMacroBeingRecorded;
+ if (macroBeingRecorded != null) {
+ for (IMacroInstructionsListener listener : fMacroInstructionsListeners) {
+ listener.beforeMacroInstructionAdded(macroInstruction);
+ }
+ macroBeingRecorded.addMacroInstruction(macroInstruction);
+ for (IMacroInstructionsListener listener : fMacroInstructionsListeners) {
+ listener.afterMacroInstructionAdded(macroInstruction);
+ }
+ }
+ }
+
+ /**
+ * Adds a macro instruction to be added to the current macro being recorded. The
+ * difference between this method and
+ * {@link #addMacroInstruction(IMacroInstruction)} is that it's meant to be used
+ * when an event may trigger the creation of multiple macro instructions and
+ * only one of those should be recorded.
+ *
+ * For instance, if a given KeyDown event is recorded in a StyledText and later
+ * an action is triggered by this event, the recorded action should overwrite
+ * the KeyDown event.
+ *
+ * @param macroInstruction
+ * the macro instruction to be added to the macro currently being
+ * recorded.
+ * @param event
+ * the event that triggered the creation of the macro instruction to
+ * be added. If there are multiple macro instructions added for the
+ * same event, only the one with the highest priority will be kept
+ * (if 2 events have the same priority, the last one will replace the
+ * previous one).
+ * @param priority
+ * the priority of the macro instruction being added (to be compared
+ * against the priority of other added macro instructions for the
+ * same event).
+ * @throws CancelMacroRecordingException
+ * @see #addMacroInstruction(IMacroInstruction)
+ */
+ public void addMacroInstruction(IMacroInstruction macroInstruction, Object event, int priority)
+ throws CancelMacroRecordingException {
+ ComposableMacro macroBeingRecorded = fMacroBeingRecorded;
+ if (macroBeingRecorded != null) {
+ for (IMacroInstructionsListener listener : fMacroInstructionsListeners) {
+ listener.beforeMacroInstructionAdded(macroInstruction);
+ }
+ if (macroBeingRecorded.addMacroInstruction(macroInstruction, event, priority)) {
+ for (IMacroInstructionsListener listener : fMacroInstructionsListeners) {
+ listener.afterMacroInstructionAdded(macroInstruction);
+ }
+ }
+ }
+ }
+
+ private static final class MacroRecordContext implements IMacroRecordContext {
+
+ private final Map<Object, Object> ctx = new HashMap<>();
+
+ @Override
+ public Object get(String key) {
+ return ctx.get(key);
+ }
+
+ @Override
+ public void set(String key, Object value) {
+ ctx.put(key, value);
+ }
+ }
+
+ /**
+ * Toggles the macro record (either starts recording or stops an existing
+ * record).
+ *
+ * @param macroService
+ * service to record macros.
+ * @param macroInstructionIdToFactory
+ * a mapping of the available macro instruction ids to the factory
+ * which is able to recreate the related macro instruction.
+ */
+ public void toggleMacroRecord(final EMacroService macroService,
+ Map<String, IMacroInstructionFactory> macroInstructionIdToFactory) {
+ if (fIsPlayingBack) {
+ // Can't toggle the macro record mode while playing back.
+ return;
+ }
+ if (fMacroBeingRecorded == null) {
+ // Start recording
+ fMacroRecordContext = new MacroRecordContext();
+ fMacroBeingRecorded = new ComposableMacro(macroInstructionIdToFactory);
+ for (IMacroStateListener listener : this.fStateListeners) {
+ if (listener instanceof IMacroStateListener1) {
+ IMacroStateListener1 macroStateListener = (IMacroStateListener1) listener;
+ SafeRunner.run(() -> macroStateListener.onMacroRecordContextCreated(fMacroRecordContext));
+ }
+ }
+ if (!notifyMacroStateChange(macroService, StateChange.RECORD_STARTED)) {
+ stopRecording(macroService);
+ }
+ } else {
+ stopRecording(macroService);
+ }
+ }
+
+ /**
+ * Stops the macro recording.
+ *
+ * @param macroService
+ * service to record macros.
+ */
+ private void stopRecording(final EMacroService macroService) {
+ try {
+ fMacroBeingRecorded.clearCachedInfo();
+ if (fMacroBeingRecorded.getLength() > 0) {
+ // No point in saving an empty macro.
+ saveTemporaryMacro(fMacroBeingRecorded);
+ fLastMacro = fMacroBeingRecorded;
+ }
+ } finally {
+ fMacroBeingRecorded = null;
+ // Notify only after setting fMacroBeingRecorded to null (which will
+ // make isRecording return false on the notification);
+ notifyMacroStateChange(macroService, StateChange.RECORD_FINISHED);
+ fMacroRecordContext = null;
+ }
+ }
+
+ /**
+ * Helper class to store a path an a time.
+ */
+ public static final class PathAndTime {
+
+ public final Path fPath;
+ public final long fLastModified;
+
+ public PathAndTime(Path path, long lastModified) {
+ this.fPath = path;
+ this.fLastModified = lastModified;
+ }
+
+ }
+
+ /**
+ * @param macro
+ * the macro to be recorded as a temporary macro.
+ */
+ private void saveTemporaryMacro(ComposableMacro macro) {
+ if (fMacrosDirectories == null || this.fMacrosDirectories.length == 0) {
+ return;
+ }
+ // The first one is the one we use as a working directory to store
+ // temporary macros.
+ File macroDirectory = this.fMacrosDirectories[0];
+ if (!macroDirectory.isDirectory()) {
+ Activator.log(new RuntimeException(
+ String.format("Unable to save macro. Expected: %s to be a directory.", macroDirectory))); //$NON-NLS-1$
+ return;
+ }
+
+ List<PathAndTime> pathAndTime = listTemporaryMacrosPathAndTime(macroDirectory);
+
+ try {
+ Path tempFile = Files.createTempFile(Paths.get(macroDirectory.toURI()), TEMP_MACRO_PREFIX, JS_EXT);
+ Files.write(tempFile, macro.toJSBytes(), StandardOpenOption.CREATE, StandardOpenOption.WRITE,
+ StandardOpenOption.TRUNCATE_EXISTING);
+ } catch (IOException e) {
+ Activator.log(e);
+ return; // Can't create file at expected place;
+ }
+
+ // Remove older files
+ while (pathAndTime.size() >= fMaxNumberOfTemporaryMacros) {
+ PathAndTime removeFile = pathAndTime.remove(pathAndTime.size() - 1);
+ try {
+ Files.deleteIfExists(removeFile.fPath);
+ } catch (Exception e) {
+ Activator.log(e);
+ }
+ }
+ }
+
+ /**
+ * @param macroDirectory
+ * the directory from where we should get the temporary macros.
+ *
+ * @return The path/time for the temporary macros at a given directory as an
+ * array list sorted such that the last element is the oldest one and
+ * the first is the newest.
+ */
+ public List<PathAndTime> listTemporaryMacrosPathAndTime(File macroDirectory) {
+ // It's a sorted list and not a tree map to deal with the case of
+ // multiple times pointing to the same file (although hard to happen,
+ // it's not impossible).
+ List<PathAndTime> pathAndTime = new ArrayList<>();
+
+ try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get(macroDirectory.toURI()),
+ new DirectoryStream.Filter<Path>() {
+
+ @Override
+ public boolean accept(Path entry) {
+ String name = entry.getFileName().toString().toLowerCase();
+ return name.startsWith(TEMP_MACRO_PREFIX) && name.endsWith(JS_EXT);
+ }
+ })) {
+ for (Path p : directoryStream) {
+ pathAndTime.add(new PathAndTime(p, Files.getLastModifiedTime(p).to(TimeUnit.NANOSECONDS)));
+ }
+ } catch (IOException e1) {
+ Activator.log(e1);
+ }
+
+ // Sort by reversed modified time (because it's faster to remove the
+ // last element from an ArrayList later on).
+ Collections.sort(pathAndTime, new Comparator<PathAndTime>() {
+
+ @Override
+ public int compare(PathAndTime o1, PathAndTime o2) {
+ return Long.compare(o2.fLastModified, o1.fLastModified);
+ }
+ });
+ return pathAndTime;
+ }
+
+ /**
+ * Notifies that a macro state change occurred (see
+ * {@link org.eclipse.e4.core.macros.IMacroStateListener}).
+ *
+ * @return false if a listener has throw a CancelMacroException and true
+ * otherwise.
+ */
+ private boolean notifyMacroStateChange(final EMacroService macroService, final StateChange stateChange) {
+ boolean okToGo = true;
+ for (final IMacroStateListener listener : fStateListeners) {
+ try {
+ listener.macroStateChanged(macroService, stateChange);
+ } catch (CancelMacroException e) {
+ okToGo = false;
+ } catch (Exception e) {
+ Activator.log(e);
+ }
+ }
+ return okToGo;
+ }
+
+ /**
+ * Playback the last recorded macro.
+ *
+ * @param macroService
+ * the macro service (used to notify listeners of the change.
+ * @param macroPlaybackContext
+ * a context to be used to playback the macro (passed to the macro to
+ * be played back).
+ * @throws MacroPlaybackException
+ * if some error happens when running the macro.
+ */
+ public void playbackLastMacro(EMacroService macroService, final IMacroPlaybackContext macroPlaybackContext)
+ throws MacroPlaybackException {
+ if (fLastMacro != null && !fIsPlayingBack) {
+ // Note that we can play back while recording, but we can't change
+ // the recording mode while playing back.
+ fIsPlayingBack = true;
+ try {
+ fMacroPlaybackContext = macroPlaybackContext;
+ for (IMacroStateListener listener : this.fStateListeners) {
+ if (listener instanceof IMacroStateListener1) {
+ IMacroStateListener1 macroStateListener = (IMacroStateListener1) listener;
+ SafeRunner.run(() -> macroStateListener.onMacroPlaybackContextCreated(macroPlaybackContext));
+ }
+ }
+
+ if (notifyMacroStateChange(macroService, StateChange.PLAYBACK_STARTED)) {
+ fLastMacro.playback(macroPlaybackContext);
+ }
+ } finally {
+ fIsPlayingBack = false;
+ notifyMacroStateChange(macroService, StateChange.PLAYBACK_FINISHED);
+ fMacroPlaybackContext = null;
+ }
+ }
+ }
+
+ /**
+ * A list with the listeners to be notified of changes in the macro service.
+ */
+ private final ListenerList<IMacroStateListener> fStateListeners = new ListenerList<>();
+
+ /**
+ * Adds a macro listener to be notified on changes in the macro record/playback
+ * state.
+ *
+ * @param listener
+ * the listener to be added.
+ */
+ public void addMacroStateListener(IMacroStateListener listener) {
+ fStateListeners.add(listener);
+ }
+
+ /**
+ * @param listener
+ * the macro listener which should no longer be notified of changes.
+ */
+ public void removeMacroStateListener(IMacroStateListener listener) {
+ fStateListeners.remove(listener);
+ }
+
+ /**
+ * @return the currently registered listeners.
+ */
+ public IMacroStateListener[] getMacroStateListeners() {
+ Object[] listeners = fStateListeners.getListeners();
+ IMacroStateListener[] macroStateListeners = new IMacroStateListener[listeners.length];
+ System.arraycopy(listeners, 0, macroStateListeners, 0, listeners.length);
+ return macroStateListeners;
+ }
+
+ /**
+ * Reloads the macros available from the disk.
+ */
+ public void reloadMacros() {
+ for (File macroDirectory : this.fMacrosDirectories) {
+ if (macroDirectory.isDirectory()) {
+ List<PathAndTime> listPathsAndTimes = listTemporaryMacrosPathAndTime(macroDirectory);
+ if (listPathsAndTimes.size() > 0) {
+ this.fLastMacro = new SavedJSMacro(listPathsAndTimes.get(0).fPath.toFile());
+ return; // Load the last from the first directory (others aren't used for the last
+ // macro).
+ }
+ } else {
+ Activator.log(new RuntimeException(String.format("Expected: %s to be a directory.", macroDirectory))); //$NON-NLS-1$
+ }
+ }
+ }
+
+ private final ListenerList<IMacroInstructionsListener> fMacroInstructionsListeners = new ListenerList<>();
+
+ /**
+ * Adds a macro instructions listener (it may be added to validate the current
+ * state of the macro recording).
+ *
+ * @param macroInstructionsListener
+ * the listener for macro instructions.
+ */
+ public void addMacroInstructionsListener(IMacroInstructionsListener macroInstructionsListener) {
+ fMacroInstructionsListeners.add(macroInstructionsListener);
+ }
+
+ /**
+ * Removes a macro instructions listener.
+ *
+ * @param macroInstructionsListener
+ * the listener for macro instructions.
+ */
+ public void removeMacroInstructionsListener(IMacroInstructionsListener macroInstructionsListener) {
+ fMacroInstructionsListeners.remove(macroInstructionsListener);
+ }
+
+ /**
+ * @return the macro record context created when macro record started or null if
+ * it's not currently recording.
+ */
+ public IMacroRecordContext getMacroRecordContext() {
+ return fMacroRecordContext;
+ }
+
+ /**
+ * @return the macro playback context created when macro playback started or
+ * null if it's not currently recording.
+ */
+ public IMacroPlaybackContext getMacroPlaybackContext() {
+ return fMacroPlaybackContext;
+ }
+
+ /**
+ * @return the number of macro instructions in the macro currently recorded or
+ * -1 if no macro is being recorded.
+ */
+ public int getLenOfMacroBeingRecorded() {
+ if (fMacroBeingRecorded != null) {
+ return fMacroBeingRecorded.getLength();
+ }
+ return -1;
+ }
+
+
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroPlaybackContextImpl.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroPlaybackContextImpl.java
new file mode 100644
index 0000000..c45cb1e
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroPlaybackContextImpl.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroInstructionFactory;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+
+/**
+ * Provides a way to recreate commands when playing back a macro.
+ */
+public class MacroPlaybackContextImpl implements IMacroPlaybackContext {
+
+ /**
+ * Map from the macro instruction id to the factory which should recreate it.
+ */
+ private Map<String, IMacroInstructionFactory> fMacroInstructionIdToFactory;
+
+ /**
+ * @param macroInstructionIdToFactory
+ * a map from the macro instruction id to the factory which should
+ * recreate it.
+ */
+ public MacroPlaybackContextImpl(Map<String, IMacroInstructionFactory> macroInstructionIdToFactory) {
+ this.fMacroInstructionIdToFactory = macroInstructionIdToFactory;
+ }
+
+ @Override
+ public IMacroInstruction createMacroInstruction(String macroInstructionId, Map<String, String> stringMap)
+ throws Exception {
+ IMacroInstructionFactory macroFactory = fMacroInstructionIdToFactory.get(macroInstructionId);
+ if (macroFactory == null) {
+ throw new RuntimeException(
+ "Unable to find IMacroInstructionFactory for macro instruction: " + macroInstructionId); //$NON-NLS-1$
+ }
+ return macroFactory.create(stringMap);
+ }
+
+ private final Map<Object, Object> ctx = new HashMap<>();
+
+ @Override
+ public Object get(String key) {
+ return ctx.get(key);
+ }
+
+ @Override
+ public void set(String key, Object value) {
+ ctx.put(key, value);
+ }
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroServiceCreationFunction.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroServiceCreationFunction.java
new file mode 100644
index 0000000..da1fd60
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroServiceCreationFunction.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros.internal;
+
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.macros.EMacroService;
+
+/**
+ * Creates a
+ * {@link org.eclipse.e4.core.macros.internal.MacroServiceImplementation} (to be
+ * bound to EMacroService).
+ *
+ * @note internal API: users should generally just get the EMacroService as a
+ * service or with @Inject. Will always return the same instance (only a
+ * single macro service is expected per application).
+ */
+public class MacroServiceCreationFunction extends ContextFunction {
+
+ private static EMacroService fService;
+
+ @Override
+ public Object compute(IEclipseContext context, String contextKey) {
+ if (fService == null) {
+ fService = ContextInjectionFactory.make(MacroServiceImplementation.class, context);
+ }
+ return fService;
+ }
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroServiceImplementation.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroServiceImplementation.java
new file mode 100644
index 0000000..8672c30
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/MacroServiceImplementation.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros.internal;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import javax.inject.Inject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.macros.Activator;
+import org.eclipse.e4.core.macros.CancelMacroRecordingException;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroInstructionFactory;
+import org.eclipse.e4.core.macros.IMacroInstructionsListener;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.IMacroRecordContext;
+import org.eclipse.e4.core.macros.IMacroStateListener;
+import org.eclipse.e4.core.macros.MacroPlaybackException;
+
+/**
+ * An implementation of the public API for dealing with macros (mostly passes
+ * things to an internal MacroManager instance and sets it up properly, dealing
+ * with the eclipse context and extension points).
+ */
+public class MacroServiceImplementation implements EMacroService {
+
+ /**
+ * The instance of the macro manager.
+ */
+ private MacroManager fMacroManager;
+
+ /**
+ * Gets the macro manager (lazily creates it if needed).
+ *
+ * @return the macro manager responsible for managing macros.
+ */
+ public MacroManager getMacroManager() {
+ if (fMacroManager == null) {
+ // user.home/.eclipse is already used by oomph and recommenders, so,
+ // it seems a good place to read additional macros which should be
+ // persisted for the user who wants to store macros across
+ // workspaces.
+ Activator plugin = Activator.getDefault();
+ File[] macrosDirectory;
+ if (plugin != null) {
+ IPath stateLocation = plugin.getStateLocation();
+ stateLocation.append("macros"); //$NON-NLS-1$
+ File userHome = new File(System.getProperty("user.home")); //$NON-NLS-1$
+ File eclipseUserHome = new File(userHome, ".eclipse"); //$NON-NLS-1$
+ File eclipseUserHomeMacros = new File(eclipseUserHome, "org.eclipse.e4.core.macros"); //$NON-NLS-1$
+ File eclipseUserHomeMacrosLoadDir = new File(eclipseUserHomeMacros, "macros"); //$NON-NLS-1$
+ if (!eclipseUserHomeMacrosLoadDir.exists()) {
+ eclipseUserHomeMacrosLoadDir.mkdirs();
+ }
+ macrosDirectory = new File[] { stateLocation.toFile(), eclipseUserHomeMacrosLoadDir };
+ // By default macros are saved/loaded under the workspace, but
+ // can also be loaded from the
+ //
+ // user.home/.eclipse/org.eclipse.e4.macros/macros
+ //
+ // directory.
+ } else {
+ macrosDirectory = new File[] {};
+ }
+ fMacroManager = new MacroManager(macrosDirectory);
+ }
+ return fMacroManager;
+ }
+
+ public static final String MACRO_INSTRUCTION_FACTORY_EXTENSION_POINT = "org.eclipse.e4.core.macros.macroInstructionsFactory"; //$NON-NLS-1$
+ public static final String MACRO_INSTRUCTION_ID = "macroInstructionId"; //$NON-NLS-1$
+ public static final String MACRO_INSTRUCTION_FACTORY_CLASS = "class"; //$NON-NLS-1$
+
+ // Globally loaded id to factory
+ private static Map<String, IMacroInstructionFactory> fCachedMacroInstructionIdToFactory;
+
+ // id to factory used in instance
+ private Map<String, IMacroInstructionFactory> fMacroInstructionIdToFactory;
+
+ public static final String MACRO_LISTENERS_EXTENSION_POINT = "org.eclipse.e4.core.macros.macroStateListeners"; //$NON-NLS-1$
+ public static final String MACRO_LISTENER_CLASS = "class"; //$NON-NLS-1$
+
+ private boolean fLoadedExtensionListeners = false;
+
+ private IEclipseContext fEclipseContext;
+
+ private IExtensionRegistry fExtensionRegistry;
+
+ @Inject
+ public MacroServiceImplementation(IEclipseContext eclipseContext, IExtensionRegistry extensionRegistry) {
+ this.fEclipseContext = eclipseContext;
+ this.fExtensionRegistry = extensionRegistry;
+ }
+
+
+ /**
+ * Loads the macro listeners provided through extension points.
+ */
+ private void loadExtensionPointsmacroStateListeners() {
+ if (!fLoadedExtensionListeners && fExtensionRegistry != null) {
+ fLoadedExtensionListeners = true;
+
+ MacroManager macroManager = getMacroManager();
+ for (IConfigurationElement ce : fExtensionRegistry
+ .getConfigurationElementsFor(MACRO_LISTENERS_EXTENSION_POINT)) {
+ String macroStateListenerClass = ce.getAttribute(MACRO_LISTENER_CLASS);
+ if (macroStateListenerClass != null) {
+ try {
+ IMacroStateListener macroStateListener = (IMacroStateListener) ce
+ .createExecutableExtension(MACRO_LISTENER_CLASS);
+ // Make sure that it has the proper eclipse context.
+ ContextInjectionFactory.inject(macroStateListener, fEclipseContext);
+ macroManager.addMacroStateListener(macroStateListener);
+ } catch (CoreException e) {
+ Activator.log(e);
+ }
+ } else {
+ Activator.log(new RuntimeException(
+ "Wrong definition for extension: " + MACRO_LISTENERS_EXTENSION_POINT + ": " + ce)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+ }
+
+ /**
+ * @return Returns the fMacroInstructionIdToFactory (creates it lazily if it
+ * still wasn't created).
+ */
+ private Map<String, IMacroInstructionFactory> getMacroInstructionIdToFactory() {
+ if (fMacroInstructionIdToFactory == null) {
+ if (fCachedMacroInstructionIdToFactory == null && fEclipseContext != null && fExtensionRegistry != null) {
+ Map<String, IMacroInstructionFactory> validMacroInstructionIds = new HashMap<>();
+ for (IConfigurationElement ce : fExtensionRegistry
+ .getConfigurationElementsFor(MACRO_INSTRUCTION_FACTORY_EXTENSION_POINT)) {
+ String macroInstructionId = ce.getAttribute(MACRO_INSTRUCTION_ID);
+ String macroInstructionFactoryClass = ce.getAttribute(MACRO_INSTRUCTION_FACTORY_CLASS);
+ if (macroInstructionId != null && macroInstructionFactoryClass != null) {
+ try {
+ IMacroInstructionFactory macroInstructionFactory = (IMacroInstructionFactory) ce
+ .createExecutableExtension(MACRO_INSTRUCTION_FACTORY_CLASS);
+
+ // Make sure that it has the proper eclipse context.
+ ContextInjectionFactory.inject(macroInstructionFactory, fEclipseContext);
+ validMacroInstructionIds.put(macroInstructionId, macroInstructionFactory);
+ } catch (CoreException e) {
+ Activator.log(e);
+ }
+ } else {
+ Activator.log(new RuntimeException("Wrong definition for extension: " //$NON-NLS-1$
+ + MACRO_INSTRUCTION_FACTORY_EXTENSION_POINT + ": " + ce)); //$NON-NLS-1$
+ }
+ }
+ fCachedMacroInstructionIdToFactory = validMacroInstructionIds;
+ }
+ fMacroInstructionIdToFactory = fCachedMacroInstructionIdToFactory;
+ }
+ return fMacroInstructionIdToFactory;
+ }
+
+ @Override
+ public boolean isRecording() {
+ if (fMacroManager == null) {
+ // Avoid creating if possible
+ return false;
+ }
+ return getMacroManager().isRecording();
+ }
+
+ @Override
+ public boolean isPlayingBack() {
+ if (fMacroManager == null) {
+ // Avoid creating if possible
+ return false;
+ }
+ return getMacroManager().isPlayingBack();
+ }
+
+ @Override
+ public void addMacroInstruction(IMacroInstruction macroInstruction) {
+ if (this.isRecording()) {
+ try {
+ getMacroManager().addMacroInstruction(macroInstruction);
+ } catch (CancelMacroRecordingException e) {
+ stopMacroRecording();
+ }
+ }
+ }
+
+ @Override
+ public void addMacroInstruction(IMacroInstruction macroInstruction, Object event, int priority) {
+ if (this.isRecording()) {
+ try {
+ getMacroManager().addMacroInstruction(macroInstruction, event, priority);
+ } catch (CancelMacroRecordingException e) {
+ stopMacroRecording();
+ }
+ }
+ }
+
+ /**
+ * Stops the macro recording.
+ */
+ private void stopMacroRecording() {
+ if (this.isRecording()) {
+ this.toggleMacroRecord();
+ }
+ }
+
+ @Override
+ public void toggleMacroRecord() {
+ loadExtensionPointsmacroStateListeners();
+ getMacroManager().toggleMacroRecord(this, getMacroInstructionIdToFactory());
+ }
+
+ @Override
+ public void playbackLastMacro() throws MacroPlaybackException {
+ loadExtensionPointsmacroStateListeners();
+ IMacroPlaybackContext macroPlaybackContext = new MacroPlaybackContextImpl(getMacroInstructionIdToFactory());
+ getMacroManager().playbackLastMacro(this, macroPlaybackContext);
+ }
+
+ @Override
+ public void addMacroStateListener(IMacroStateListener listener) {
+ getMacroManager().addMacroStateListener(listener);
+ }
+
+ @Override
+ public void removeMacroStateListener(IMacroStateListener listener) {
+ getMacroManager().removeMacroStateListener(listener);
+ }
+
+ @Override
+ public IMacroRecordContext getMacroRecordContext() {
+ return getMacroManager().getMacroRecordContext();
+ }
+
+ @Override
+ public IMacroPlaybackContext getMacroPlaybackContext() {
+ return getMacroManager().getMacroPlaybackContext();
+ }
+
+ /**
+ * Note that this is only available in this implementation, not on the public
+ * API (EMacroService). Needed for testing.
+ *
+ * @return the currently registered listeners.
+ */
+ public IMacroStateListener[] getMacroStateListeners() {
+ return getMacroManager().getMacroStateListeners();
+ }
+
+ /**
+ * A map which maps accepted command ids when recording a macro to whether they
+ * should be recorded as a macro instruction to be played back later on.
+ */
+ private Map<String, Boolean> fCustomizedCommandIds;
+
+ /**
+ * @return a set with the commands that are accepted when macro recording.
+ */
+ private Map<String, Boolean> getInternalmacroCommandCustomization() {
+ if (fCustomizedCommandIds == null) {
+ fCustomizedCommandIds = new HashMap<>();
+ if (fEclipseContext != null) {
+ IExtensionRegistry registry = fEclipseContext.get(IExtensionRegistry.class);
+ if (registry != null) {
+ for (IConfigurationElement ce : registry
+ .getConfigurationElementsFor("org.eclipse.e4.core.macros.macroCommandCustomization")) { //$NON-NLS-1$
+ if ("customizedCommand".equals(ce.getName()) && ce.getAttribute("id") != null //$NON-NLS-1$ //$NON-NLS-2$
+ && ce.getAttribute("recordMacroInstruction") != null) { //$NON-NLS-1$
+ Boolean recordMacroInstruction = Boolean
+ .parseBoolean(ce.getAttribute("recordMacroInstruction")) //$NON-NLS-1$
+ ? Boolean.TRUE
+ : Boolean.FALSE;
+ fCustomizedCommandIds.put(ce.getAttribute("id"), recordMacroInstruction); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ return fCustomizedCommandIds;
+ }
+
+ @Override
+ public boolean getRecordCommandInMacro(String commandId) {
+ Map<String, Boolean> macromacroCommandCustomization = getInternalmacroCommandCustomization();
+ Boolean recordMacro = macromacroCommandCustomization.get(commandId);
+ if (recordMacro == null) {
+ return true;
+ }
+ return recordMacro;
+ }
+
+ @Override
+ public void setRecordCommandInMacro(String commandId, boolean recordMacroInstruction) {
+ getInternalmacroCommandCustomization().put(commandId, recordMacroInstruction);
+ }
+
+ @Override
+ public void addMacroInstructionsListener(IMacroInstructionsListener macroInstructionsListener) {
+ getMacroManager().addMacroInstructionsListener(macroInstructionsListener);
+ }
+
+ @Override
+ public void removeMacroInstructionsListener(IMacroInstructionsListener macroInstructionsListener) {
+ getMacroManager().removeMacroInstructionsListener(macroInstructionsListener);
+ }
+
+ @Override
+ public int getLenOfMacroBeingRecorded() {
+ return getMacroManager().getLenOfMacroBeingRecorded();
+ }
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/Messages.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/Messages.java
new file mode 100644
index 0000000..5734d1d
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/Messages.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros.internal;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @since 0.1.0
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.e4.core.macros.internal.messages"; //$NON-NLS-1$
+ public static String SavedJSMacro_MacrosEvalError;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/SavedJSMacro.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/SavedJSMacro.java
new file mode 100644
index 0000000..84403b4
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/SavedJSMacro.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.core.macros.internal;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.SimpleScriptContext;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.MacroPlaybackException;
+
+/**
+ * Actually loads a macro from a JS file to be played back. Works with the
+ * contents saved from {@link ComposableMacro#toJSBytes()}.
+ * <p>
+ * Currently the saved macro is a JavaScript file to be played back again with a
+ * "runMacro" function which may have multiple "runMacroInstruction" calls to
+ * run a macro instruction which was previously persisted with
+ * {@link IMacroInstruction#toMap()}.
+ * </p>
+ */
+public class SavedJSMacro implements IMacro {
+
+ /**
+ * The file which contains the contents of the macro.
+ */
+ private final File fFile;
+
+ /**
+ * Creates a macro which is backed up by the contents of a javascript file.
+ *
+ * @param file
+ * the file with the contents of the macro.
+ */
+ public SavedJSMacro(File file) {
+ this.fFile = file;
+ }
+
+ /**
+ * Static method to be called when playing back a macro to run a macro
+ * instruction..
+ *
+ * @param macroPlaybackContext
+ * the context for the macro playback.
+ * @param macroInstructionId
+ * the id of the macro instruction to be executed.
+ * @param macroInstructionParameters
+ * the parameters to create the macro instruction.
+ * @throws Exception
+ * if something happened when creating the macro instruction or
+ * actually executing it.
+ */
+ @SuppressWarnings({ "rawtypes" })
+ public static void runMacroInstruction(IMacroPlaybackContext macroPlaybackContext, String macroInstructionId,
+ Object macroInstructionParameters) throws Exception {
+ Map<String, String> stringMap = new HashMap<>();
+ Map m = (Map) macroInstructionParameters;
+ Set<Map.Entry> entrySet = m.entrySet();
+ for (Map.Entry entry : entrySet) {
+ Object key = entry.getKey();
+ Object value = entry.getValue();
+ stringMap.put(key.toString(), value.toString());
+ }
+ IMacroInstruction macroInstruction = macroPlaybackContext.createMacroInstruction(macroInstructionId, stringMap);
+ macroInstruction.execute(macroPlaybackContext);
+ }
+
+ @Override
+ public void playback(IMacroPlaybackContext macroPlaybackContext) throws MacroPlaybackException {
+ ScriptEngineManager manager = new ScriptEngineManager();
+ ScriptEngine engine = manager.getEngineByName("nashorn"); //$NON-NLS-1$
+ SimpleScriptContext context = new SimpleScriptContext();
+ context.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
+ Bindings engineScope = context.getBindings(ScriptContext.ENGINE_SCOPE);
+
+ // Setup the default context.
+ engineScope.put("__macroPlaybackContext", macroPlaybackContext); //$NON-NLS-1$
+
+ try {
+ engine.eval("" + //$NON-NLS-1$
+ "__macro = Java.type('org.eclipse.e4.core.macros.internal.SavedJSMacro');\n" //$NON-NLS-1$
+ + "function runMacroInstruction(macroMacroInstructionId, macroInstructionParameters){" //$NON-NLS-1$
+ + " __macro.runMacroInstruction(__macroPlaybackContext, macroMacroInstructionId, macroInstructionParameters);" //$NON-NLS-1$
+ + "}" //$NON-NLS-1$
+ + "", context); //$NON-NLS-1$
+
+ // The contents to execute are actually built at:
+ // org.eclipse.e4.core.macros.internal.ComposableMacro.toJSBytes()
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(new FileInputStream(fFile), "UTF-8"))) { //$NON-NLS-1$
+ // Let any exception running it go through.
+ // It should define a runMacro() method which we can run later on.
+ engine.eval(reader, context);
+
+ // Actually run the macro now.
+ engine.eval("runMacro();", context); //$NON-NLS-1$
+ }
+ } catch (Exception e) {
+ throw new MacroPlaybackException(
+ MessageFormat.format(Messages.SavedJSMacro_MacrosEvalError, e.getMessage()), e);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/messages.properties b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/messages.properties
new file mode 100644
index 0000000..3677ab5
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/internal/messages.properties
@@ -0,0 +1 @@
+SavedJSMacro_MacrosEvalError=Error when evaluating macro:\n\n{0}
diff --git a/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/package-info.java b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/package-info.java
new file mode 100644
index 0000000..0a71baf
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.macros/src/org/eclipse/e4/core/macros/package-info.java
@@ -0,0 +1,257 @@
+package org.eclipse.e4.core.macros;
+
+/**
+ * Package providing abstractions for dealing with macro record/playback.
+ *
+ * <p>
+ * The basic idea in this implementation is that the macro plugin is a thin
+ * layer used to record macro instructions and then play it back. The actual
+ * work is done on other plugins, which should be macro-aware.
+ * </p>
+ *
+ * <p>
+ * The macro recording doesn't only map to text editions. Anything done in the
+ * IDE could be recorded in a macro to be played back later on. For instance, it
+ * may be possible to record and playback changes to preferences, importing some
+ * git repository, finding text, etc. Later on, when playing it back, it should
+ * be even possible to ask if the user wants to edit some of the values which
+ * were saved during record.
+ * </p>
+ *
+ * <p>
+ * Still, note that while that support may be possible in the future, currently
+ * the implementation only targets the text editor and its operations.
+ * </p>
+ *
+ *
+ * <hr/>
+ * <h3>Rationale</h3>
+ *
+ * <p>
+ * The basic idea is that editors listen or detect when macro record mode is
+ * active and upon entering macro mode, they make sure actions are properly
+ * tracked so that they can be played back accordingly.
+ * </p>
+ *
+ * <p>
+ * -- note that it's important that things are not the other way around: the
+ * macro plugin is a thin layer to start/stop macro recording and provide the
+ * basic abstractions and management of macros, it's up to the clients to be
+ * aware that they are in macro record mode and act accordingly, issuing
+ * commands to be recorded and later played back.
+ * </p>
+ *
+ * <hr/>
+ * <h3>Related APIs</h3>
+ *
+ * <p>
+ * Note that currently the only APIs available are exposed as interfaces:
+ * </p>
+ *
+ * <p>
+ * {@link org.eclipse.e4.core.macros.EMacroService} can be used to:
+ *
+ * <ul>
+ * <li>query the current record/playback state;</li>
+ * <li>listen changes in the current record/playback state;</li>
+ * <li>add macro instructions when in record mode;</li>
+ * <li>start and stop the macro record;</li>
+ * <li>playback a previous macro;</li>
+ * <li>get commands customization from the
+ * org.eclipse.e4.core.macros.macroCommandCustomization extension point;</li>
+ * <li>programatically customize commands.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * {@link org.eclipse.e4.core.macros.IMacroInstruction}: A macro is actually
+ * composed of multiple macro instructions. Each time the user does some action
+ * which should be recorded, a macro instruction should be created and added to
+ * the EMacroService. (note that currently the basic macro abstraction -- IMacro
+ * -- is only internally available, but the idea is that a macro is composed of
+ * multiple macro instructions).
+ * </p>
+ *
+ * <p>
+ * {@link org.eclipse.e4.core.macros.IMacroInstructionFactory}: provides a way
+ * to recreate an {@link org.eclipse.e4.core.macros.IMacroInstruction} from its
+ * id and persisted contents.
+ * </p>
+ *
+ * <p>
+ * {@link org.eclipse.e4.core.macros.IMacroPlaybackContext}: received by a macro
+ * instruction when it's being played back.
+ * </p>
+ *
+ * <p>
+ * {@link org.eclipse.e4.core.macros.IMacroStateListener}: listener to hear
+ * changes in the record/playback state (added to the EMacroService).
+ * </p>
+ *
+ *
+ * <hr/>
+ * <h3>Actually dealing with macro record/playback</h3>
+ *
+ * <p>
+ * Clients should:
+ * <ul>
+ * <li>listen when a macro record will start to set up their internal state and
+ * add if needed, add listeners which records actions/events when they happen so
+ * that they're properly added the macro being recorded;</li>
+ * <li>listen when a macro record session finished to remove any used listener
+ * and restore previous state;</li>
+ * <li>listen when a macro playback starts/finishes and set up/reset the
+ * internal state properly</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * -- Note: it's possible for the user to start a record mode and playback a
+ * previous macro in such a mode (although the opposite is not true).
+ * </p>
+ *
+ * <h4>Scenario 1:</h4>
+ *
+ * <p>
+ * Setting up state when entering macro record/playback mode:
+ * </p>
+ *
+ * <p>
+ * This gives an example where some state must be set for both macro and record
+ * mode (i.e.: disabling code-completion) and in the record mode it also has to
+ * record keypresses to be played back later on.
+ * </p>
+ *
+ * <pre>
+ * public class MyMacroAwareEditor implements IMacroStateListener {
+ *
+ * public void init(final IEditorSite site) {
+ * fMacroService = site.getService(EMacroService.class);
+ * if (fMacroService != null) {
+ * // Start listening to the service so that events are properly
+ * // recorded.
+ * fMacroService.addmacroStateListener(this);
+ * if (fMacroService.isRecording() || fMacroService.isPlayingBack()) {
+ * this.macroStateChanged(fMacroService);
+ * }
+ * }
+ * }
+ *
+ * public final void macroStateChanged(EMacroService macroService) {
+ * // Note: state must be set with care because record/playback may
+ * // happen simultaneously.
+ * if (macroService.isRecording() || macroService.isPlayingBack()) {
+ * // Code completion disabled in both, record and playback.
+ * this.disableCodeCompletion();
+ * } else {
+ * this.enableCodeCompletion();
+ * }
+ *
+ * if (macroService.isRecording()) {
+ * this.startRecordingKeyEvents(macroService);
+ * } else {
+ * this.endRecordingKeyEvents();
+ * }
+ * }
+ *
+ * protected void startRecordingKeyEvents(final EMacroService macroService) {
+ * // Note: if simultaneously recording/playing back, this may be called
+ * // multiple times.
+ * if (this.fKeyEventListener == null) {
+ * this.fKeyEventListener = new Listener() {
+ * @Override
+ * public void handleEvent(Event event) {
+ * if (event.type == SWT.KeyDown && fMacroService.isRecording()) {
+ * fMacroService.addMacroInstruction(new KeyDownMacroInstruction(event));
+ * }
+ * }
+ * };
+ * this.addListener(SWT.KeyDown, this.fKeyEventListener);
+ * }
+ * }
+ *
+ * protected void endRecordingKeyEvents() {
+ * if (this.fKeyEventListener != null) {
+ * this.removeListener(SWT.KeyDown, this.fKeyEventListener);
+ * this.fKeyEventListener = null;
+ * }
+ * }
+ *
+ * }
+ * </pre>
+ *
+ * <p>
+ * An actual implementation using this strategy is:
+ * </p>
+ *
+ * <p>
+ * {@link org.eclipse.ui.workbench.texteditor.macros.internal.MacroStyledTextInstaller}
+ * </p>
+ *
+ *
+ * <h4>Scenario 2</h4>
+ *
+ * <p>
+ * Just issuing macro instructions when no setup is needed:
+ * </p>
+ *
+ * <pre>
+ * public class MyMacroAwareClass {
+ *
+ * @Inject
+ * EMacroService fMacroService;
+ *
+ * public void run(String myCommand) {
+ * ...
+ * // Actually run command
+ * if(fMacroService.isRecording()){
+ * fMacroService.addMacroInstruction(new MyRunCommandMacroInstruction(myCommand));
+ * }
+ * }
+ * }
+ *
+ * </pre>
+ *
+ * <p>
+ * An actual implementation using this strategy is:
+ * {@link org.eclipse.e4.ui.macros.internal.keybindings.CommandManagerExecutionListener}
+ * </p>
+ *
+ * <p>
+ * -- Note: commands registered through the eclipse commands extensions will be
+ * already recorded by default if they aren't registered in the
+ * org.eclipse.e4.core.macros.macroCommandCustomization extension point and
+ * their activation will already be recorded for proper playback by default (so,
+ * clients only actually need to customize actions which currently aren't
+ * implemented as eclipse actions or to disable recording of some eclipse
+ * action).
+ * </p>
+ *
+ * <hr/>
+ * <h3>Macro playback</h3>
+ *
+ * <p>
+ * After a command is actually added to the EMacroService and a record session
+ * is finished, all the recorded IMacroInstructions will be saved to disk using
+ * the contents of their
+ * {@link org.eclipse.e4.core.macros.IMacroInstruction#toMap()} method to enable
+ * playing it back later on.
+ * </p>
+ *
+ * <p>
+ * Afterward, when it's time to play a macro instruction back, the contents of
+ * the map are gotten from disk and will be recreated through factories
+ * registered in the org.eclipse.e4.core.macros.macroInstructionsFactory
+ * extension point (so it's important to note that if a custom macro instruction
+ * is created, a factory to recreate it must be registered).
+ * </p>
+ *
+ * <p>
+ * On playback, the macro instruction must perform the same action which was
+ * recorded (so, for instance, if a command to delete the current line of the
+ * editor was issued, on playback the current line of the current editor must be
+ * deleted).
+ * </p>
+ *
+ *
+ **/
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.e4.ui.macros.jdt/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index f42de36..0000000
--- a/bundles/org.eclipse.e4.ui.macros.jdt/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,7 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
-org.eclipse.jdt.core.compiler.compliance=1.7
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.7
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.macros.jdt/META-INF/MANIFEST.MF
deleted file mode 100644
index 697afe5..0000000
--- a/bundles/org.eclipse.e4.ui.macros.jdt/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,9 +0,0 @@
-Manifest-Version: 1.0
-Bundle-ManifestVersion: 2
-Bundle-Name: E4 Macros - JDT Support
-Bundle-SymbolicName: org.eclipse.e4.ui.macros.jdt;singleton:=true
-Bundle-Version: 0.1.0.qualifier
-Bundle-Vendor: Eclipse.org
-Fragment-Host: org.eclipse.jdt.ui
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Require-Bundle: org.eclipse.e4.ui.macros
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/fragment.xml b/bundles/org.eclipse.e4.ui.macros.jdt/fragment.xml
deleted file mode 100644
index ebc2bae..0000000
--- a/bundles/org.eclipse.e4.ui.macros.jdt/fragment.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?eclipse version="3.4"?>
-<fragment>
- <extension
- point="org.eclipse.e4.ui.macros.hooks">
- <hook
- class="org.eclipse.e4.ui.macros.jdt.JdtContentAssistMacroHook" />
- </extension>
-
- <extension
- point="org.eclipse.e4.ui.macros.commands">
- <whitelist id="org.eclipse.jdt.ui.edit.text.java.open.editor" /> <!-- F3 -->
-
- <blacklist id="org.eclipse.jdt.ui.edit.text.java.open.hierarchy" /> <!-- Ctrl-T -->
- <blacklist id="org.eclipse.jdt.ui.edit.text.java.show.outline" /> <!-- Ctrl-O -->
-
- <!-- Quick Fix -->
- <blacklist id="org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals" />
- <blacklist id="org.eclipse.jdt.ui.edit.text.java.open.type.hierarchy" /> <!-- F4 -->
- <blacklist id="org.eclipse.jdt.ui.navigate.open.type" /> <!-- Ctrl-Shift-O -->
- </extension>
-</fragment>
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/pom.xml b/bundles/org.eclipse.e4.ui.macros.jdt/pom.xml
deleted file mode 100644
index dd9b241..0000000
--- a/bundles/org.eclipse.e4.ui.macros.jdt/pom.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
--->
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.eclipse.e4.ui</groupId>
- <artifactId>e4-ui-aggregator</artifactId>
- <version>0.17.0-SNAPSHOT</version>
- <relativePath>../../</relativePath>
- </parent>
-
- <artifactId>org.eclipse.e4.ui.macros.jdt</artifactId>
- <version>0.1.0-SNAPSHOT</version>
- <packaging>eclipse-plugin</packaging>
-</project>
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/src/org/eclipse/e4/ui/macros/jdt/JdtContentAssistMacroHook.java b/bundles/org.eclipse.e4.ui.macros.jdt/src/org/eclipse/e4/ui/macros/jdt/JdtContentAssistMacroHook.java
deleted file mode 100644
index 198c6e7..0000000
--- a/bundles/org.eclipse.e4.ui.macros.jdt/src/org/eclipse/e4/ui/macros/jdt/JdtContentAssistMacroHook.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.macros.jdt;
-
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.e4.ui.macros.IMacroHook;
-import org.eclipse.jdt.internal.ui.JavaPlugin;
-import org.eclipse.jdt.ui.PreferenceConstants;
-import org.eclipse.jface.preference.IPreferenceStore;
-
-/**
- * Disable content assist for macro recording and playback as it introduces
- * non-determinism: we can't be certain of the ordering of the items shown is
- * stable.
- */
-public class JdtContentAssistMacroHook implements IMacroHook {
- private boolean autoActivates;
-
- @Override
- public IStatus start(Mode mode) {
- IPreferenceStore preferenceStore = JavaPlugin.getDefault().getPreferenceStore();
- autoActivates = preferenceStore.getBoolean(PreferenceConstants.CODEASSIST_AUTOACTIVATION);
- preferenceStore.setValue(PreferenceConstants.CODEASSIST_AUTOACTIVATION, false);
- return Status.OK_STATUS;
- }
-
- @Override
- public void stop(Mode mode) {
- IPreferenceStore preferenceStore = JavaPlugin.getDefault().getPreferenceStore();
- preferenceStore.setValue(PreferenceConstants.CODEASSIST_AUTOACTIVATION, autoActivates);
- }
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/.gitignore b/bundles/org.eclipse.e4.ui.macros/.gitignore
new file mode 100644
index 0000000..ae3c172
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/bundles/org.eclipse.e4.ui.macros/.project b/bundles/org.eclipse.e4.ui.macros/.project
index 1bc56d2..fb2d5bb 100644
--- a/bundles/org.eclipse.e4.ui.macros/.project
+++ b/bundles/org.eclipse.e4.ui.macros/.project
@@ -20,9 +20,20 @@
<arguments>
</arguments>
</buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
</natures>
</projectDescription>
diff --git a/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.core.runtime.prefs b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.jdt.core.prefs
index f42de36..e2f298f 100644
--- a/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.jdt.core.prefs
+++ b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.jdt.core.prefs
@@ -1,7 +1,424 @@
eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
-org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=error
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=error
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=error
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=120
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..b058cde
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,125 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_blocks=false
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup_profile=org.eclipse.jdt.ui.default.eclipse_clean_up_profile
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=org.eclipse.jdt.ui.default.eclipse_profile
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment"/><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=true
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=false
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.pde.api.tools.prefs b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 0000000..a09ec9c
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,97 @@
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+API_USE_SCAN_FIELD_SEVERITY=Error
+API_USE_SCAN_METHOD_SEVERITY=Error
+API_USE_SCAN_TYPE_SEVERITY=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_JAVADOC_TAG=Warning
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Error
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+MISSING_EE_DESCRIPTIONS=Warning
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Warning
+automatically_removed_unused_problem_filters=false
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Error
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.pde.prefs b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.pde.prefs
new file mode 100644
index 0000000..2ce5047
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/.settings/org.eclipse.pde.prefs
@@ -0,0 +1,32 @@
+compilers.f.unresolved-features=1
+compilers.f.unresolved-plugins=1
+compilers.incompatible-environment=1
+compilers.p.build=1
+compilers.p.build.bin.includes=1
+compilers.p.build.encodings=2
+compilers.p.build.java.compiler=2
+compilers.p.build.java.compliance=1
+compilers.p.build.missing.output=1
+compilers.p.build.output.library=1
+compilers.p.build.source.library=1
+compilers.p.build.src.includes=1
+compilers.p.deprecated=1
+compilers.p.discouraged-class=1
+compilers.p.internal=1
+compilers.p.missing-packages=1
+compilers.p.missing-version-export-package=2
+compilers.p.missing-version-import-package=1
+compilers.p.missing-version-require-bundle=1
+compilers.p.no-required-att=0
+compilers.p.not-externalized-att=1
+compilers.p.unknown-attribute=1
+compilers.p.unknown-class=1
+compilers.p.unknown-element=1
+compilers.p.unknown-identifier=1
+compilers.p.unknown-resource=1
+compilers.p.unresolved-ex-points=0
+compilers.p.unresolved-import=0
+compilers.s.create-docs=false
+compilers.s.doc-folder=doc
+compilers.s.open-tags=1
+eclipse.preferences.version=1
diff --git a/bundles/org.eclipse.e4.ui.macros/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.macros/META-INF/MANIFEST.MF
index 30e4f3b..0180cbe 100644
--- a/bundles/org.eclipse.e4.ui.macros/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.ui.macros/META-INF/MANIFEST.MF
@@ -3,23 +3,34 @@
Bundle-Name: E4 Macro Recording and Playback
Bundle-SymbolicName: org.eclipse.e4.ui.macros;singleton:=true
Bundle-Version: 0.1.0.qualifier
+Bundle-Activator: org.eclipse.e4.ui.macros.Activator
Bundle-Vendor: Eclipse.org
-Require-Bundle: org.eclipse.e4.ui.bindings;bundle-version="0.10.200",
- org.eclipse.e4.ui.model.workbench;bundle-version="1.1.100",
+Export-Package: org.eclipse.e4.ui.macros,
+ org.eclipse.e4.ui.macros.internal;x-friends:="org.eclipse.ui.workbench.texteditor.macros",
+ org.eclipse.e4.ui.macros.internal.actions;x-friends:="org.eclipse.e4.ui.bindings.tests",
+ org.eclipse.e4.ui.macros.internal.keybindings;x-friends:="org.eclipse.e4.ui.bindings.tests"
+Require-Bundle: org.eclipse.e4.ui.model.workbench;bundle-version="1.1",
org.eclipse.e4.ui.workbench.renderers.swt,
org.eclipse.e4.ui.workbench,
org.eclipse.ui.workbench;resolution:=optional,
- org.eclipse.jface;bundle-version="3.11.0",
- org.eclipse.swt;bundle-version="3.104.0",
- org.eclipse.osgi
-Bundle-RequiredExecutionEnvironment: JavaSE-1.7
-Bundle-ActivationPolicy: lazy
+ org.eclipse.jface;bundle-version="3.11",
+ org.eclipse.swt;bundle-version="3.104",
+ org.eclipse.osgi,
+ org.eclipse.ui;bundle-version="3.108",
+ org.eclipse.core.commands,
+ org.eclipse.e4.core.contexts;bundle-version="1.0",
+ org.eclipse.e4.core.di;bundle-version="1.1",
+ org.eclipse.e4.core.macros;bundle-version="0.1",
+ org.eclipse.ui.console,
+ org.eclipse.e4.ui.bindings;bundle-version="0.11",
+ org.eclipse.e4.core.services;bundle-version="2.0",
+ org.eclipse.e4.core.commands
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: javax.inject,
- org.eclipse.core.runtime;version="3.5.0",
+ org.eclipse.core.runtime;version="3.5",
org.eclipse.e4.core.commands,
org.eclipse.e4.core.contexts,
org.eclipse.e4.core.di,
org.eclipse.e4.core.di.annotations,
- org.osgi.framework;version="1.8.0"
-Export-Package: org.eclipse.e4.ui.internal.macros,
- org.eclipse.e4.ui.macros
+ org.osgi.framework;version="1.8"
+Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.e4.ui.macros/OSGI-INF/l10n/bundle.properties b/bundles/org.eclipse.e4.ui.macros/OSGI-INF/l10n/bundle.properties
new file mode 100644
index 0000000..9603a46
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/OSGI-INF/l10n/bundle.properties
@@ -0,0 +1,5 @@
+#Properties file for org.eclipse.e4.ui.macros
+category.macros.name = Macros
+command.macro_playback.name = Playback Last Macro
+toolbar.macro.label = Macro
+command.toggle_macro_record.label = Toggle Macro Record
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.ui.macros/build.properties b/bundles/org.eclipse.e4.ui.macros/build.properties
index 5dc29cb..163cdac 100644
--- a/bundles/org.eclipse.e4.ui.macros/build.properties
+++ b/bundles/org.eclipse.e4.ui.macros/build.properties
@@ -2,6 +2,5 @@
bin.includes = META-INF/,\
.,\
plugin.xml,\
- fragment.e4xmi
+ OSGI-INF/
source.. = src/
-src.includes = schema/
diff --git a/bundles/org.eclipse.e4.ui.macros/icons/full/dtool16/macro_playback.png b/bundles/org.eclipse.e4.ui.macros/icons/full/dtool16/macro_playback.png
new file mode 100644
index 0000000..a5ca398
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/icons/full/dtool16/macro_playback.png
Binary files differ
diff --git a/bundles/org.eclipse.e4.ui.macros/icons/full/dtool16/macro_record.png b/bundles/org.eclipse.e4.ui.macros/icons/full/dtool16/macro_record.png
new file mode 100644
index 0000000..2b203d5
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/icons/full/dtool16/macro_record.png
Binary files differ
diff --git a/bundles/org.eclipse.e4.ui.macros/plugin.xml b/bundles/org.eclipse.e4.ui.macros/plugin.xml
index 89e82db..907a6cb 100644
--- a/bundles/org.eclipse.e4.ui.macros/plugin.xml
+++ b/bundles/org.eclipse.e4.ui.macros/plugin.xml
@@ -1,121 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
-<?eclipse version="3.4"?>
<plugin>
- <extension-point id="hooks" name="Macro Recording and Playback Hooks" schema="schema/hooks.exsd"/>
- <extension-point id="commands" name="Describe commands that have been vetted or disallowed for macros" schema="schema/commands.exsd"/>
- <extension
- id="macroinstaller"
- point="org.eclipse.e4.workbench.model">
- <processor
- apply="always"
- beforefragment="true"
- class="org.eclipse.e4.ui.internal.macros.MacroRecorderInstaller">
- </processor>
+
+ <extension point="org.eclipse.e4.core.macros.macroCommandCustomization">
+
+ <!-- We should be able to stop the macro recording after the recording started. -->
+ <customizedCommand id="org.eclipse.e4.ui.macros.toggleRecordMacro" recordMacroInstruction="false"/>
+
+ <!-- Playback is Ok during recording, but only its side-effects are recorded, not the command itself. -->
+ <customizedCommand id="org.eclipse.e4.ui.macros.macroPlayback" recordMacroInstruction="false"/>
+
+ <!-- Disable recording of actions not related to the editor (which the user may choose to do
+ but shouldn't interfere with the macro recording). -->
+ <customizedCommand id="org.eclipse.ui.window.nextEditor" recordMacroInstruction="false"/>
+ <customizedCommand id="org.eclipse.ui.window.nextView" recordMacroInstruction="false"/>
+ <customizedCommand id="org.eclipse.ui.window.nextPerspective" recordMacroInstruction="false"/>
+ <customizedCommand id="org.eclipse.ui.navigate.showInQuickMenu" recordMacroInstruction="false"/>
+ <customizedCommand id="org.eclipse.ui.window.showKeyAssist" recordMacroInstruction="false"/>
+ <customizedCommand id="org.eclipse.ui.window.openEditorDropDown" recordMacroInstruction="false"/>
+ <customizedCommand id="org.eclipse.ui.window.quickAccess" recordMacroInstruction="false"/>
+ <customizedCommand id="org.eclipse.ui.edit.findReplace" recordMacroInstruction="false"/>
</extension>
<extension
- point="org.eclipse.e4.ui.macros.commands">
- <whitelist id="org.eclipse.e4.ui.macros.toggleRecording" />
-
- <whitelist id="org.eclipse.ui.edit.cut" />
- <whitelist id="org.eclipse.ui.edit.copy" />
- <whitelist id="org.eclipse.ui.edit.paste" />
- <whitelist id="org.eclipse.ui.edit.delete" />
- <whitelist id="org.eclipse.ui.edit.undo" />
- <whitelist id="org.eclipse.ui.edit.redo" />
- <whitelist id="org.eclipse.ui.edit.text.join.lines" />
- <whitelist id="org.eclipse.ui.edit.text.delete.line" />
- <whitelist id="org.eclipse.ui.edit.text.removeTrailingWhitespace" />
- <whitelist id="org.eclipse.ui.edit.text.delete.line.to.beginning" />
- <whitelist id="org.eclipse.ui.edit.text.delete.line.to.end" />
- <whitelist id="org.eclipse.ui.edit.text.cut.line" />
- <whitelist id="org.eclipse.ui.edit.text.cut.line.to.beginning" />
- <whitelist id="org.eclipse.ui.edit.text.cut.line.to.end" />
- <whitelist id="org.eclipse.ui.edit.findIncremental" />
- <whitelist id="org.eclipse.ui.edit.findIncrementalReverse" />
- <whitelist id="org.eclipse.ui.edit.revertToSaved" />
- <whitelist id="org.eclipse.ui.edit.text.goto.lineUp" />
- <whitelist id="org.eclipse.ui.edit.text.goto.lineDown" />
- <whitelist id="org.eclipse.ui.edit.text.goto.lineStart" />
- <whitelist id="org.eclipse.ui.edit.text.goto.lineEnd" />
- <whitelist id="org.eclipse.ui.edit.text.goto.columnPrevious" />
- <whitelist id="org.eclipse.ui.edit.text.goto.columnNext" />
- <whitelist id="org.eclipse.ui.edit.text.goto.pageUp" />
- <whitelist id="org.eclipse.ui.edit.text.goto.pageDown" />
- <whitelist id="org.eclipse.ui.edit.text.goto.wordPrevious" />
- <whitelist id="org.eclipse.ui.edit.text.goto.wordNext" />
- <whitelist id="org.eclipse.ui.edit.text.goto.textStart" />
- <whitelist id="org.eclipse.ui.edit.text.goto.textEnd" />
- <whitelist id="org.eclipse.ui.edit.text.goto.windowStart" />
- <whitelist id="org.eclipse.ui.edit.text.goto.windowEnd" />
- <whitelist id="org.eclipse.ui.edit.text.scroll.lineUp" />
- <whitelist id="org.eclipse.ui.edit.text.scroll.lineDown" />
- <whitelist id="org.eclipse.ui.edit.text.select.lineUp" />
- <whitelist id="org.eclipse.ui.edit.text.select.lineDown" />
- <whitelist id="org.eclipse.ui.edit.text.select.lineStart" />
- <whitelist id="org.eclipse.ui.edit.text.select.lineEnd" />
- <whitelist id="org.eclipse.ui.edit.text.select.columnPrevious" />
- <whitelist id="org.eclipse.ui.edit.text.select.columnNext" />
- <whitelist id="org.eclipse.ui.edit.text.select.pageUp" />
- <whitelist id="org.eclipse.ui.edit.text.select.pageDown" />
- <whitelist id="org.eclipse.ui.edit.text.select.wordPrevious" />
- <whitelist id="org.eclipse.ui.edit.text.select.wordNext" />
- <whitelist id="org.eclipse.ui.edit.text.select.textStart" />
- <whitelist id="org.eclipse.ui.edit.text.select.textEnd" />
- <whitelist id="org.eclipse.ui.edit.text.select.windowStart" />
- <whitelist id="org.eclipse.ui.edit.text.select.windowEnd" />
- <whitelist id="org.eclipse.ui.edit.text.deletePrevious" />
- <whitelist id="org.eclipse.ui.edit.text.deleteNext" />
- <whitelist id="org.eclipse.ui.edit.text.deletePreviousWord" />
- <whitelist id="org.eclipse.ui.edit.text.deleteNextWord" />
- <whitelist id="org.eclipse.ui.edit.text.shiftRight" />
- <whitelist id="org.eclipse.ui.edit.text.shiftLeft" />
- <whitelist id="org.eclipse.ui.edit.text.toggleOverwrite" />
- <whitelist id="org.eclipse.ui.edit.text.smartEnter" />
- <whitelist id="org.eclipse.ui.edit.text.smartEnterInverse" />
- <whitelist id="org.eclipse.ui.edit.text.moveLineUp" />
- <whitelist id="org.eclipse.ui.edit.text.moveLineDown" />
- <whitelist id="org.eclipse.ui.edit.text.copyLineUp" />
- <whitelist id="org.eclipse.ui.edit.text.copyLineDown" />
- <whitelist id="org.eclipse.ui.edit.text.upperCase" />
- <whitelist id="org.eclipse.ui.edit.text.lowerCase" />
- <whitelist id="org.eclipse.ui.edit.text.toggleBlockSelectionMode" />
- <whitelist id="org.eclipse.ui.edit.text.toggleInsertMode" />
- <whitelist id="org.eclipse.ui.edit.text.recenter" />
- <whitelist id="org.eclipse.ui.edit.text.open.hyperlink" />
-
- <whitelist id="org.eclipse.ui.window.showViewMenu" />
+ point="org.eclipse.e4.core.macros.macroInstructionsFactory">
+ <macroInstructionsFactory
+ class="org.eclipse.e4.ui.macros.internal.keybindings.MacroInstructionForParameterizedCommandFactory"
+ macroInstructionId="Command">
+ </macroInstructionsFactory>
</extension>
-
- <extension
- point="org.eclipse.e4.ui.macros.commands">
- <!-- can't play a macro during recording -->
- <blacklist id="org.eclipse.e4.ui.macros.playRecording" />
- <!-- non deterministic order -->
- <blacklist id="org.eclipse.ui.edit.text.contentAssist.proposals" />
-
- <!-- Can tap F6 repeatedly to alternate, which we can't intercept -->
- <blacklist id="org.eclipse.ui.window.nextEditor" />
- <blacklist id="org.eclipse.ui.window.previousEditor" />
- <blacklist id="org.eclipse.ui.window.nextView" />
- <blacklist id="org.eclipse.ui.window.previousView" />
- <blacklist id="org.eclipse.ui.window.nextPerspective" />
- <blacklist id="org.eclipse.ui.window.previousPerspective" />
-
- <blacklist id="org.eclipse.ui.file.openWorkspace" />
- <blacklist id="org.eclipse.ui.file.newQuickMenu" />
- <blacklist id="org.eclipse.ui.edit.text.openLocalFile" />
- <blacklist id="org.eclipse.ui.navigate.showInQuickMenu" />
- <blacklist id="org.eclipse.ui.navigate.goToResource" />
- <blacklist id="org.eclipse.ui.navigate.openResource" />
- <blacklist id="org.eclipse.ui.project.openProject" />
- <blacklist id="org.eclipse.ui.project.closeProject" />
- <blacklist id="org.eclipse.ui.project.closeUnrelatedProjects" />
- <blacklist id="org.eclipse.ui.project.properties" />
- <blacklist id="org.eclipse.ui.edit.addTask" />
- <blacklist id="org.eclipse.ui.navigate.selectWorkingSets" />
+ <extension
+ point="org.eclipse.e4.core.macros.macroStateListeners">
+ <macroStateListener
+ class="org.eclipse.e4.ui.macros.internal.keybindings.CommandManagerExecutionListenerInstaller">
+ </macroStateListener>
+ <macroStateListener
+ class="org.eclipse.e4.ui.macros.internal.actions.KeepMacroUIUpdated">
+ </macroStateListener>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.commands">
+ <category
+ id="org.eclipse.e4.ui.macros.category"
+ name="%category.macros.name">
+ </category>
+ <command
+ categoryId="org.eclipse.e4.ui.macros.category"
+ defaultHandler="org.eclipse.e4.ui.macros.internal.actions.ToggleMacroRecordAction"
+ id="org.eclipse.e4.ui.macros.toggleRecordMacro"
+ name="%command.toggle_macro_record.label">
+ </command>
+ <command
+ categoryId="org.eclipse.e4.ui.macros.category"
+ defaultHandler="org.eclipse.e4.ui.macros.internal.actions.MacroPlaybackAction"
+ id="org.eclipse.e4.ui.macros.macroPlayback"
+ name="%command.macro_playback.name">
+ </command>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.menus">
+ <menuContribution
+ allPopups="false"
+ locationURI="toolbar:org.eclipse.ui.main.toolbar?after=additions">
+ <toolbar
+ id="org.eclipse.e4.ui.macros.toolbar"
+ label="%toolbar.macro.label">
+ <command
+ commandId="org.eclipse.e4.ui.macros.toggleRecordMacro"
+ icon="icons/full/dtool16/macro_record.png"
+ label="%command.toggle_macro_record.label"
+ style="toggle">
+ </command>
+ <command
+ commandId="org.eclipse.e4.ui.macros.macroPlayback"
+ icon="icons/full/dtool16/macro_playback.png"
+ label="%command.macro_playback.name"
+ style="push">
+ </command>
+ </toolbar>
+ </menuContribution>
</extension>
</plugin>
diff --git a/bundles/org.eclipse.e4.ui.macros/pom.xml b/bundles/org.eclipse.e4.ui.macros/pom.xml
index 32d5a80..93c827a 100644
--- a/bundles/org.eclipse.e4.ui.macros/pom.xml
+++ b/bundles/org.eclipse.e4.ui.macros/pom.xml
@@ -1,16 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
+<!--
+ Copyright (c) 2017 Fabio Zadrozny and others.
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Distribution License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/org/documents/edl-v10.php
+
+ Contributors:
+ Fabio Zadrozny - initial implementation
-->
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.e4.ui</groupId>
diff --git a/bundles/org.eclipse.e4.ui.macros/schema/commands.exsd b/bundles/org.eclipse.e4.ui.macros/schema/commands.exsd
deleted file mode 100644
index 4f8d4b3..0000000
--- a/bundles/org.eclipse.e4.ui.macros/schema/commands.exsd
+++ /dev/null
@@ -1,128 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<!-- Schema file written by PDE -->
-<schema targetNamespace="org.eclipse.e4.ui.macros" xmlns="http://www.w3.org/2001/XMLSchema">
-<annotation>
- <appinfo>
- <meta.schema plugin="org.eclipse.e4.ui.macros" id="commands" name="Describe commands that have been vetted or disallowed for macros"/>
- </appinfo>
- <documentation>
- [Enter description of this extension point.]
- </documentation>
- </annotation>
-
- <element name="extension">
- <annotation>
- <appinfo>
- <meta.element />
- </appinfo>
- </annotation>
- <complexType>
- <choice minOccurs="1" maxOccurs="unbounded">
- <element ref="blacklist"/>
- <element ref="whitelist"/>
- </choice>
- <attribute name="point" type="string" use="required">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="id" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="name" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- <appinfo>
- <meta.attribute translatable="true"/>
- </appinfo>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <element name="whitelist">
- <annotation>
- <documentation>
- A black-listed command, one that is always allowed during keyboard macro recording
- </documentation>
- </annotation>
- <complexType>
- <attribute name="id" type="string" use="required">
- <annotation>
- <documentation>
- A command identifier
- </documentation>
- <appinfo>
- <meta.attribute kind="identifier" basedOn="org.eclipse.ui.commands/command/@id"/>
- </appinfo>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <element name="blacklist">
- <annotation>
- <documentation>
- A black-listed command, one that is never allowed during keyboard macro recording
- </documentation>
- </annotation>
- <complexType>
- <attribute name="id" type="string" use="required">
- <annotation>
- <documentation>
- A command identifier
- </documentation>
- <appinfo>
- <meta.attribute kind="identifier" basedOn="org.eclipse.ui.commands/command/@id"/>
- </appinfo>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <annotation>
- <appinfo>
- <meta.section type="since"/>
- </appinfo>
- <documentation>
- [Enter the first release in which this extension point appears.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="examples"/>
- </appinfo>
- <documentation>
- [Enter extension point usage example here.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="apiinfo"/>
- </appinfo>
- <documentation>
- [Enter API information here.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="implementation"/>
- </appinfo>
- <documentation>
- [Enter information about supplied implementation of this extension point.]
- </documentation>
- </annotation>
-
-
-</schema>
diff --git a/bundles/org.eclipse.e4.ui.macros/schema/hooks.exsd b/bundles/org.eclipse.e4.ui.macros/schema/hooks.exsd
deleted file mode 100644
index a84e0c9..0000000
--- a/bundles/org.eclipse.e4.ui.macros/schema/hooks.exsd
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<!-- Schema file written by PDE -->
-<schema targetNamespace="org.eclipse.e4.ui.macros" xmlns="http://www.w3.org/2001/XMLSchema">
-<annotation>
- <appinfo>
- <meta.schema plugin="org.eclipse.e4.ui.macros" id="hooks" name="Macro Recording and Playback Hooks"/>
- </appinfo>
- <documentation>
- Provides hooks for packages to prepare for a macro being recorded.
- </documentation>
- </annotation>
-
- <element name="extension">
- <annotation>
- <appinfo>
- <meta.element />
- </appinfo>
- </annotation>
- <complexType>
- <choice>
- <element ref="hook" minOccurs="1" maxOccurs="unbounded"/>
- </choice>
- <attribute name="point" type="string" use="required">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="id" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- </annotation>
- </attribute>
- <attribute name="name" type="string">
- <annotation>
- <documentation>
-
- </documentation>
- <appinfo>
- <meta.attribute translatable="true"/>
- </appinfo>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <element name="hook">
- <annotation>
- <documentation>
- A hook is notified before and after a macro is recorded or re-play. They are typically used to disable non-deterministic behaviours in the UI (i.e., where the results or ordering of results may change on subsequent re-invocations).
- </documentation>
- </annotation>
- <complexType>
- <attribute name="class" type="string" use="required">
- <annotation>
- <documentation>
- The hook class.
- </documentation>
- <appinfo>
- <meta.attribute kind="java" basedOn=":org.eclipse.e4.ui.macros.IMacroHook"/>
- </appinfo>
- </annotation>
- </attribute>
- </complexType>
- </element>
-
- <annotation>
- <appinfo>
- <meta.section type="since"/>
- </appinfo>
- <documentation>
- [Enter the first release in which this extension point appears.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="examples"/>
- </appinfo>
- <documentation>
- [Enter extension point usage example here.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="apiinfo"/>
- </appinfo>
- <documentation>
- [Enter API information here.]
- </documentation>
- </annotation>
-
- <annotation>
- <appinfo>
- <meta.section type="implementation"/>
- </appinfo>
- <documentation>
- [Enter information about supplied implementation of this extension point.]
- </documentation>
- </annotation>
-
-
-</schema>
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ApplicationMacroPlayer.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ApplicationMacroPlayer.java
deleted file mode 100644
index 3020c30..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ApplicationMacroPlayer.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.eclipse.e4.ui.macros.IMacroAction;
-import org.eclipse.e4.ui.model.application.MApplication;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Shell;
-
-public class ApplicationMacroPlayer {
- @Inject
- MApplication application;
- @Inject
- Display display;
-
- private LinkedList<IMacroAction> recording;
-
- public void replay() {
- recording = new LinkedList<>((List<IMacroAction>) application.getTransientData()
- .get(ApplicationMacroRecorder.ACTIVE_RECORDING_MACRO_KEY));
- if (recording == null || recording.isEmpty()) {
- System.out.println("Recording is empty");
- return;
- }
-
- hookListeners();
- Event e = new Event();
- e.display = display;
- while (!display.isDisposed() && processNext(e)) {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- }
- unhookListeners();
- }
-
- /** Return true if still more to come */
- private boolean processNext(Event e) {
- if (recording.isEmpty()) {
- unhookListeners();
- // System.out.println("REPLAY FINISHED");
- return false;
- }
- IMacroAction nextAction = recording.peek();
-
- switch (nextAction.process(e)) {
- case NEXT:
- // System.out.println("PROCESSED " + nextAction);
- recording.removeFirst();
- return true;
- case WAITING:
- // FIXME: set display timeout
- // System.out.println("WAITING ON " + nextAction);
- return true;
- case ABORT:
- default:
- unhookListeners();
- System.out.println("REPLAY ABORTED");
- return false;
- }
- }
-
- private void hookListeners() {
- display.addFilter(SWT.Activate, shellActivatedListener);
- display.addFilter(SWT.FocusIn, focusInListener);
- }
-
- private void unhookListeners() {
- display.removeFilter(SWT.Activate, shellActivatedListener);
- display.removeFilter(SWT.FocusIn, focusInListener);
- }
-
- private Listener shellActivatedListener = new Listener() {
- @Override
- public void handleEvent(Event event) {
- if (event.widget instanceof Shell) {
- processNext(event);
- }
- }
- };
-
- private Listener focusInListener = new Listener() {
- @Override
- public void handleEvent(Event event) {
- processNext(event);
- }
- };
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ApplicationMacroRecorder.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ApplicationMacroRecorder.java
deleted file mode 100644
index a7d8989..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ApplicationMacroRecorder.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.eclipse.e4.core.commands.EHandlerService;
-import org.eclipse.e4.ui.macros.IMacroAction;
-import org.eclipse.e4.ui.macros.IMacroActionProcessor;
-import org.eclipse.e4.ui.model.application.MApplication;
-
-public class ApplicationMacroRecorder implements IMacroActionProcessor {
- static final String MACRO_RECORDING_KEY = "macro:recorded";
- static final String ACTIVE_RECORDING_MACRO_KEY = "macro:current";
-
- @Inject
- MApplication application;
-
- @Inject
- EHandlerService handlerService;
-
- @Override
- public void started() {
- application.getTransientData().put(ACTIVE_RECORDING_MACRO_KEY, new ArrayList<IMacroAction>());
- }
-
- @Override
- public void finished() {
- @SuppressWarnings("unchecked")
- List<IMacroAction> recording = (List<IMacroAction>) application.getTransientData()
- .get(ACTIVE_RECORDING_MACRO_KEY);
- if (recording != null && !recording.isEmpty()) {
- application.getTransientData().put(MACRO_RECORDING_KEY, recording);
- }
- }
-
- @Override
- public void aborted() {
- application.getTransientData().remove(ACTIVE_RECORDING_MACRO_KEY);
- }
-
- @Override
- public void process(IMacroAction action) {
- List<IMacroAction> recording = (List<IMacroAction>) application.getTransientData()
- .get(ACTIVE_RECORDING_MACRO_KEY);
- recording.add(action);
- }
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/DebuggingProcessor.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/DebuggingProcessor.java
deleted file mode 100644
index 67b8c3b..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/DebuggingProcessor.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros;
-
-import org.eclipse.e4.ui.macros.BaseProcessor;
-import org.eclipse.e4.ui.macros.IMacroAction;
-import org.eclipse.e4.ui.macros.IMacroActionProcessor;
-
-public class DebuggingProcessor implements IMacroActionProcessor {
- private IMacroActionProcessor delegate = new BaseProcessor();
-
- public void setDelegateRecorder(IMacroActionProcessor delegate) {
- this.delegate = delegate;
- }
-
- public void started() {
- System.out.println(">> STARTED");
- delegate.started();
- }
-
- public void finished() {
- System.out.println(">> FINISHED");
- delegate.finished();
- }
-
- public void aborted() {
- System.out.println(">> ABORTED");
- delegate.finished();
- }
-
- @Override
- public void process(IMacroAction action) {
- System.out.println(">> " + action.toString());
- delegate.process(action);
- }
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/GestureInterpreter.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/GestureInterpreter.java
deleted file mode 100644
index 821c407..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/GestureInterpreter.java
+++ /dev/null
@@ -1,486 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.inject.Inject;
-
-import org.eclipse.core.commands.Command;
-import org.eclipse.core.commands.CommandManager;
-import org.eclipse.core.commands.ExecutionEvent;
-import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.core.commands.IExecutionListener;
-import org.eclipse.core.commands.NotHandledException;
-import org.eclipse.core.commands.Parameterization;
-import org.eclipse.core.commands.ParameterizedCommand;
-import org.eclipse.core.commands.common.NotDefinedException;
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.IExtensionRegistry;
-import org.eclipse.e4.core.commands.EHandlerService;
-import org.eclipse.e4.core.contexts.IEclipseContext;
-import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher;
-import org.eclipse.e4.ui.internal.macros.actions.InsertKeyStroke;
-import org.eclipse.e4.ui.internal.macros.actions.InvokeCommand;
-import org.eclipse.e4.ui.internal.macros.actions.WaitForShellActivation;
-import org.eclipse.e4.ui.internal.macros.actions.WaitForWidgetFocus;
-import org.eclipse.e4.ui.macros.IMacroAction;
-import org.eclipse.e4.ui.macros.IMacroActionProcessor;
-import org.eclipse.e4.ui.model.application.MApplication;
-import org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem;
-import org.eclipse.jface.action.ActionContributionItem;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.action.IContributionItem;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.osgi.util.NLS;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.MenuItem;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-import org.eclipse.swt.widgets.Widget;
-import org.eclipse.ui.internal.ActionSetContributionItem;
-import org.eclipse.ui.menus.CommandContributionItem;
-
-/**
- * Responsible for translating UI events into macro actions and sending them
- * along to interested parties implementing {@link IMacroActionProcessor} (e.g.,
- * to record the actions for future playback, or provide a UI/visualization).
- *
- * The idea was this interpreter would act as an orchestrator of multiple
- * sources that produce {@link IMacroAction}s. But there are sufficiently
- * intertwined that we've just kept them together for now.
- */
-public class GestureInterpreter {
- private static Class<?> commandContributionItemClass;
-
- static {
- try {
- commandContributionItemClass = Class.forName("org.eclipse.ui.menus.CommandContributionItem");
- } catch (Exception e) {
- /* ignore */
- }
- }
-
- @Inject
- private MApplication application;
-
- @Inject
- private IEclipseContext context;
-
- @Inject
- private Display display;
-
- @Inject
- private CommandManager commandManager;
-
- @Inject
- private KeyBindingDispatcher dispatcher;
-
- @Inject
- EHandlerService handlerService;
-
- @Inject
- IExtensionRegistry registry;
-
- /** Notified of macro actions */
- private List<IMacroActionProcessor> processors = Collections
- .synchronizedList(new LinkedList<IMacroActionProcessor>());
-
- /**
- * Controls whether events should be turned into macro actions; used to
- * ignore events when popping up macro-related dialogs
- */
- private boolean listeningPaused = false;
-
- /******* Command white-listing and black-listing *******/
- private static final String MACRO_COMMANDS_EXTPT = "org.eclipse.e4.ui.macros.commands";
- private static final String NAME_BLACKLIST = "blacklist";
- private static final String NAME_WHITELIST = "whitelist";
- private static final String ATTR_ID = "id";
-
- private Set<String> whitelistedCommandIds;
- private Set<String> blacklistedCommandIds;
-
-
-
- /** SWT.KeyDown listener to turn key presses into {@link IMacroAction}s */
- private Listener keyDownListener = new Listener() {
- @Override
- public void handleEvent(Event event) {
- dispatcher.getKeyDownFilter().handleEvent(event);
- if (listeningPaused) {
- return;
- }
- if (event.widget instanceof Control && shouldIgnore(event)) {
- return;
- }
- // if not swallowed by the key dispatcher
- if (event.doit && (event.keyCode & SWT.KEY_MASK) != SWT.NONE) {
- // List<KeyStroke> strokes =
- // KeyBindingDispatcher.generatePossibleKeyStrokes(event);
- // System.out.println(">> keyCode: " + event.keyCode + "
- // Strokes: " + strokes);
- inject(new InsertKeyStroke(event, event.widget));
- }
- }
- };
-
- /**
- * SWT.Selection listener for menu and toolbar selections to pull out
- * commands
- */
- private Listener menuToolbarSelectionListener = new Listener() {
- @Override
- public void handleEvent(Event event) {
- if (listeningPaused) {
- return;
- }
- // we're only interested in MenuItem and ToolItems
- if (event.widget instanceof Control || shouldIgnore(event)) {
- return;
- }
-
- Object object = event.widget.getData();
- if (!processPotentialCommand(object)) {
- abort();
- MessageDialog.openError(null, "Unknown Action", "Command cannot be determined from this item");
- }
- }
- };
-
- /**
- * SWT.Activate listener for shells
- */
- private Listener shellActivatedListener = new Listener() {
- @Override
- public void handleEvent(Event event) {
- if (listeningPaused) {
- return;
- }
- // should we track shell-activation because of a click in that
- // window vs a command that opens a new Shell?
- if (event.widget instanceof Shell && !shouldIgnore(event)) {
- inject(new WaitForShellActivation(event.widget));
- }
- }
- };
-
- /**
- * SWT.FocusIn listener
- */
- private Listener focusInListener = new Listener() {
- @Override
- public void handleEvent(Event event) {
- if (listeningPaused) {
- return;
- }
- if (event.widget instanceof Control && !shouldIgnore(event)) {
- inject(new WaitForWidgetFocus(event.widget));
- }
- }
- };
-
- /** Turn successful command executions into actions */
- private IExecutionListener commandExecutionListener = new IExecutionListener() {
- private Map<String, ParameterizedCommand> inProgress = new HashMap<>();
-
- @Override
- public void preExecute(String commandId, ExecutionEvent event) {
- // System.out.println("preExecute: " + commandId);
- if (listeningPaused) {
- return;
- }
- try {
- if (!checkWhitelistedCommand(event.getCommand())) {
- return;
- }
- ParameterizedCommand pc = ParameterizedCommand.generateCommand(event.getCommand(),
- event.getParameters());
- inProgress.put(commandId, pc);
- } catch (NotDefinedException e) {
- // ignore
- }
- }
-
- @Override
- public void postExecuteSuccess(String commandId, Object returnValue) {
- // System.out.println("postExecuteSuccess: " + commandId);
- ParameterizedCommand pc = inProgress.remove(commandId);
- if (pc != null) {
- inject(new InvokeCommand(handlerService, pc));
- }
- }
-
- @Override
- public void notHandled(String commandId, NotHandledException exception) {
- // ignore these commands
- inProgress.remove(commandId);
- }
-
- @Override
- public void postExecuteFailure(String commandId, ExecutionException exception) {
- // ignore these commands
- inProgress.remove(commandId);
- }
- };
-
- /**
- * Mouse events are difficult to turn into keyboard macro actions, except
- * for menu and tool items.
- */
- private Listener mouseUpListener = new Listener() {
- @Override
- public void handleEvent(Event event) {
- if (listeningPaused) {
- return;
- }
- // Ignore SWT.MouseUp events on Menu and ToolBar as they're
- // turned into SWT.Selection events on the corresponding item
- // and handled in our SWT.Selection listener
- if (!(event.widget instanceof Menu) && !(event.widget instanceof ToolBar)) {
- // use asyncExec as any mouse and key events may be dispatched
- // to the MessageDialog instead
- event.display.asyncExec(new Runnable() {
- @Override
- public void run() {
- abort();
- MessageDialog.openError(null, "Macro Recording Aborted",
- "Mouse click cannot be incorporated into macro");
- }
- });
- }
- }
- };
-
- /** List of {@link Shell}s that should be ignored */
- private Set<Shell> ignoredShells = new HashSet<Shell>();
-
- public void start() {
- loadCommandWhiteAndBlacklists();
- if (context != null) {
- context.set(GestureInterpreter.class, this);
- }
-
- hookListeners();
- synchronized (processors) {
- for (IMacroActionProcessor recorder : processors) {
- recorder.started();
- }
- }
- }
-
- public void finish() {
- unhookListeners();
-
- synchronized (processors) {
- for (IMacroActionProcessor recorder : processors) {
- recorder.finished();
- }
- }
- if (context != null && context.get(GestureInterpreter.class) == this) {
- context.remove(GestureInterpreter.class);
- }
- }
-
- public void abort() {
- unhookListeners();
-
- synchronized (processors) {
- for (IMacroActionProcessor recorder : processors) {
- recorder.aborted();
- }
- }
- if (context != null && context.get(GestureInterpreter.class) == this) {
- context.remove(GestureInterpreter.class);
- }
- }
-
- private void inject(IMacroAction action) {
- synchronized (processors) {
- for (IMacroActionProcessor recorder : processors) {
- recorder.process(action);
- }
- }
- }
-
- protected boolean processPotentialCommand(Object object) {
- if(object instanceof ParameterizedCommand) {
- inject(new InvokeCommand(handlerService, (ParameterizedCommand) object));
- return true;
- } else if (object instanceof IContributionItem) {
- IContributionItem item = (IContributionItem) object;
- String id = item.getId();
- if (commandContributionItemClass != null && commandContributionItemClass.isInstance(item)) {
- CommandContributionItem cci = (CommandContributionItem) item;
- return processPotentialCommand(cci.getCommand());
- } else if (item instanceof HandledContributionItem) {
- HandledContributionItem hci = (HandledContributionItem) item;
- return processPotentialCommand(hci.getModel().getWbCommand());
- } else if (item instanceof ActionContributionItem) {
- return processPotentialCommand(((ActionContributionItem) item).getAction());
- } else if (item instanceof ActionSetContributionItem) {
- return processPotentialCommand(((ActionSetContributionItem) item).getInnerItem());
- } else if (item instanceof ActionContributionItem) {
- return processPotentialCommand(((ActionContributionItem) item).getAction());
- }
- return false;
- } else if (object instanceof IAction) {
- IAction action = (IAction) object;
- if (action.getActionDefinitionId() != null) {
- Command cmd = commandManager.getCommand(action.getActionDefinitionId());
- if (cmd.isDefined()) {
- return processPotentialCommand(new ParameterizedCommand(cmd, new Parameterization[0]));
- }
- System.err.println("Unable to find referenced command: " + action.getActionDefinitionId());
- } else {
- System.err.println("We do not currently support selecting actions");
- }
- return false;
- }
- return false;
- }
-
- protected boolean shouldIgnore(Event event) {
- Shell shell = getShell(event.widget);
- while (shell != null) {
- if (ignoredShells.contains(shell)) {
- return true;
- }
- shell = (Shell) shell.getParent();
- }
- return false;
- }
-
- private static Shell getShell(Widget widget) {
- if (widget instanceof MenuItem) {
- return ((MenuItem) widget).getParent().getShell();
- } else if (widget instanceof ToolItem) {
- return ((ToolItem) widget).getParent().getShell();
- }
- return ((Control) widget).getShell();
- }
-
- private void loadCommandWhiteAndBlacklists() {
- whitelistedCommandIds = new HashSet<>();
- blacklistedCommandIds = new HashSet<>();
- String csv = application.getPersistedState().get(MACRO_COMMANDS_EXTPT + ":" + NAME_WHITELIST);
- if (csv != null) {
- Collections.addAll(whitelistedCommandIds, csv.split(","));
- }
- csv = application.getPersistedState().get(MACRO_COMMANDS_EXTPT + ":" + NAME_BLACKLIST);
- if (csv != null) {
- Collections.addAll(blacklistedCommandIds, csv.split(","));
- }
- for (IConfigurationElement ce : registry.getConfigurationElementsFor(MACRO_COMMANDS_EXTPT)) {
- if (NAME_BLACKLIST.equals(ce.getName()) && ce.getAttribute(ATTR_ID) != null) {
- blacklistedCommandIds.add(ce.getAttribute(ATTR_ID));
- } else if (NAME_WHITELIST.equals(ce.getName()) && ce.getAttribute(ATTR_ID) != null) {
- whitelistedCommandIds.add(ce.getAttribute(ATTR_ID));
- }
- }
- }
-
- protected boolean checkWhitelistedCommand(Command command) throws NotDefinedException {
- String commandId = command.getId();
- String commandName = command.getName();
- if (blacklistedCommandIds.contains(commandId)) {
- abort(); // unhooks listeners
- MessageDialog.openError(null, "Disallowed Command",
- NLS.bind("Command \"{0}\" ({1}) cannot be used during macro recording", commandName, commandId));
- return false;
- } else if (!whitelistedCommandIds.contains(commandId)) {
- pauseListeners();
- boolean shouldWhitelist = MessageDialog.openQuestion(null, "Whitelist command?",
- NLS.bind("Should \"{0}\" ({1}) be allowed for macros?", commandName, commandId));
- resumeListeners();
- if (shouldWhitelist) {
- System.err.println("FIXME: <whitelist id=\"" + commandId + "\" />");
- whitelistedCommandIds.add(commandId);
- String csv = application.getPersistedState().get(MACRO_COMMANDS_EXTPT + ":" + NAME_WHITELIST);
- application.getPersistedState().put(MACRO_COMMANDS_EXTPT + ":" + NAME_WHITELIST,
- csv == null ? commandId : csv + "," + commandId);
- } else {
- // FIXME: record the user's direction
- System.err.println("FIXME: <blacklist id=\"" + commandId + "\" />");
- // FIXME: record this more permanently
- blacklistedCommandIds.add(commandId);
- String csv = application.getPersistedState().get(MACRO_COMMANDS_EXTPT + ":" + NAME_BLACKLIST);
- application.getPersistedState().put(MACRO_COMMANDS_EXTPT + ":" + NAME_BLACKLIST,
- csv == null ? commandId : csv + "," + commandId);
- abort();
- }
- return shouldWhitelist;
- }
- return true;
- }
-
- private void resumeListeners() {
- listeningPaused = false;
- }
-
- private void pauseListeners() {
- listeningPaused = true;
- }
-
- private void hookListeners() {
- Listener keyFilter = dispatcher.getKeyDownFilter();
- display.removeFilter(SWT.KeyDown, keyFilter);
- display.removeFilter(SWT.Traverse, keyFilter);
- display.addFilter(SWT.Traverse, keyDownListener);
- display.addFilter(SWT.KeyDown, keyDownListener);
-
- display.addFilter(SWT.MouseUp, mouseUpListener);
- display.addFilter(SWT.Selection, menuToolbarSelectionListener);
- display.addFilter(SWT.Activate, shellActivatedListener);
- display.addFilter(SWT.FocusIn, focusInListener);
- commandManager.addExecutionListener(commandExecutionListener);
- }
-
- private void unhookListeners() {
- Listener keyFilter = dispatcher.getKeyDownFilter();
- display.addFilter(SWT.KeyDown, keyFilter);
- display.addFilter(SWT.Traverse, keyFilter);
- display.removeFilter(SWT.Traverse, keyDownListener);
- display.removeFilter(SWT.KeyDown, keyDownListener);
-
- display.removeFilter(SWT.MouseUp, mouseUpListener);
- display.removeFilter(SWT.Selection, menuToolbarSelectionListener);
- display.removeFilter(SWT.Activate, shellActivatedListener);
- display.removeFilter(SWT.FocusIn, focusInListener);
- commandManager.removeExecutionListener(commandExecutionListener);
- }
-
- public void addListener(IMacroActionProcessor recorder) {
- processors.add(recorder);
- }
-
- public void removeListener(IMacroActionProcessor recorder) {
- processors.remove(recorder);
- }
-
- /** Ignore events coming from the provided shell */
- public void addIgnoreShell(Shell shell) {
- ignoredShells.add(shell);
- }
-
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/MacroHooksManager.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/MacroHooksManager.java
deleted file mode 100644
index 4f5fd00..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/MacroHooksManager.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.IExtensionRegistry;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.e4.ui.macros.IMacroHook;
-import org.eclipse.e4.ui.model.application.MApplication;
-
-public class MacroHooksManager {
-
- static final String HOOKS_EXTPT = "org.eclipse.e4.ui.macros.hooks";
- static final String NAME_HOOK = "hook";
- static final String ATTR_CLASS = "class";
-
- @Inject
- private MApplication application;
-
- @Inject
- private IExtensionRegistry registry;
-
- private List<IMacroHook> hooks;
-
- public IStatus runStartHooks(IMacroHook.Mode mode) {
- if (hooks != null) {
- System.out.println(">> Hooks exist: already in progress?");
- return new Status(IStatus.ERROR, "org.eclipse.e4.ui.macros", "Macro operation already in progress");
- }
- // System.out.println(">> Running starting hooks (" + mode + ")...");
- hooks = new LinkedList<>();
- for (IConfigurationElement ce : registry.getConfigurationElementsFor(HOOKS_EXTPT)) {
- if (ce.getName().equals(NAME_HOOK) && ce.getAttribute(ATTR_CLASS) != null) {
- try {
- IMacroHook hook = (IMacroHook) ce.createExecutableExtension(ATTR_CLASS);
- IStatus rc = hook.start(mode);
- if (!rc.isOK()) {
- return rc;
- }
- hooks.add(hook);
- } catch (CoreException e) {
- System.err.println("Unable to instantiate class: " + e);
- }
- }
- }
- return Status.OK_STATUS;
- }
-
- public void runFinishHooks(IMacroHook.Mode mode) {
- // may not have been running
- if (hooks != null) {
- // System.out.println(">> Running finished hooks (" + mode +
- // ")...");
- for (IMacroHook hook : hooks) {
- hook.stop(mode);
- }
- hooks = null;
- }
- }
-
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/MacroRecorderInstaller.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/MacroRecorderInstaller.java
deleted file mode 100644
index 4da49c7..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/MacroRecorderInstaller.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros;
-
-import java.util.Comparator;
-import java.util.TreeSet;
-
-import javax.inject.Inject;
-
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.model.application.MApplication;
-import org.eclipse.e4.ui.model.application.commands.MBindingContext;
-import org.eclipse.e4.ui.model.application.commands.MBindingTable;
-import org.eclipse.e4.ui.model.application.commands.MCommand;
-import org.eclipse.e4.ui.model.application.commands.MHandler;
-import org.eclipse.e4.ui.model.application.commands.MKeyBinding;
-import org.eclipse.e4.ui.workbench.modeling.EModelService;
-import org.osgi.framework.FrameworkUtil;
-
-/**
- * E4 Model Processor to set up macro recording and playback commands
- */
-public class MacroRecorderInstaller {
- private static final String TOGGLE_RECORDING_COMMAND = "org.eclipse.e4.ui.macros.toggleRecording";
-
- private static final String PLAY_MACRO_COMMAND = "org.eclipse.e4.ui.macros.playRecording";
-
- @Inject
- private MApplication application;
-
- @Inject
- private EModelService modelService;
-
- private String bundleId = FrameworkUtil.getBundle(getClass()).getSymbolicName();
-
-
- @Execute
- public void process() {
- MCommand recordMacro = installCommand(TOGGLE_RECORDING_COMMAND, "Start/Stop recording a macro",
- "Start recording a macro or stop the current macro");
- installHandler(recordMacro, ToggleRecordingHandler.class);
- installKeyBinding("org.eclipse.ui.contexts.window", "M2+M3+M", recordMacro);
-
- MCommand replay = installCommand(PLAY_MACRO_COMMAND, "Play macro", "Replay the last recorded macro");
- installHandler(replay, ReplayMacroHandler.class);
- installKeyBinding("org.eclipse.ui.contexts.window", "M1+M2+M", replay);
- }
-
- private MCommand installCommand(String commandId, String name, String description) {
- for (MCommand cmd : application.getCommands()) {
- if (commandId.equals(cmd.getElementId())) {
- // Already exists
- return cmd;
- }
- }
-
- MCommand command = modelService.createModelElement(MCommand.class);
- command.setElementId(commandId);
- command.setCommandName(name);
- command.setDescription(description);
- command.setContributorURI("platform:/plugin/" + bundleId);
-
- application.getCommands().add(command);
- return command;
- }
-
- private MHandler installHandler(MCommand command, Class<?> handlerClass) {
- String handlerBundleId = FrameworkUtil.getBundle(handlerClass).getSymbolicName();
- String contributionURI = "bundleclass://" + handlerBundleId + "/" + handlerClass.getName();
-
- for (MHandler handler : application.getHandlers()) {
- if (contributionURI.equals(handler.getContributionURI())) {
- // Already exists
- return handler;
- }
- }
-
- MHandler handler = modelService.createModelElement(MHandler.class);
- handler.setElementId(handlerClass.getName());
- handler.setCommand(command);
- handler.setContributionURI(contributionURI);
- handler.setContributorURI("platform:/plugin/" + handlerBundleId);
- application.getHandlers().add(handler);
- return handler;
- }
-
- private MKeyBinding installKeyBinding(String bindingContextId, String keySeq, MCommand command) {
- MBindingContext bindingContext = findBindingContext(bindingContextId);
- if (bindingContext == null) {
- bindingContext = modelService.createModelElement(MBindingContext.class);
- bindingContext.setElementId(bindingContextId);
- application.getBindingContexts().add(bindingContext);
- }
-
- MBindingTable bindingTable = null;
- for (MBindingTable bt : application.getBindingTables()) {
- if (bt.getBindingContext() == bindingContext) {
- bindingTable = bt;
- break;
- }
- }
- if (bindingTable == null) {
- bindingTable = modelService.createModelElement(MBindingTable.class);
- bindingTable.setBindingContext(bindingContext);
- application.getBindingTables().add(bindingTable);
- }
- for (MKeyBinding kb : bindingTable.getBindings()) {
- if (kb.getCommand() == command) {
- // already bound
- return kb;
- }
- }
-
- MKeyBinding keyBinding = modelService.createModelElement(MKeyBinding.class);
- keyBinding.setKeySequence(keySeq);
- keyBinding.setContributorURI("platform:/plugin/" + bundleId);
- keyBinding.setCommand(command);
- bindingTable.getBindings().add(keyBinding);
- return keyBinding;
- }
-
- private MBindingContext findBindingContext(String bindingContextId) {
- TreeSet<MBindingContext> contexts = new TreeSet<>(new Comparator<MBindingContext>() {
- @Override
- public int compare(MBindingContext o1, MBindingContext o2) {
- return o1.getElementId().compareTo(o2.getElementId());
- }
- });
- contexts.addAll(application.getBindingContexts());
- while (!contexts.isEmpty()) {
- MBindingContext bc = contexts.first();
- if (bindingContextId.equals(bc.getElementId())) {
- return bc;
- }
- contexts.remove(bc);
- contexts.addAll(bc.getChildren());
- }
- return null;
- }
-
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/MacroStatusPopup.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/MacroStatusPopup.java
deleted file mode 100644
index 334ebd1..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/MacroStatusPopup.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import org.eclipse.e4.ui.macros.BaseProcessor;
-import org.eclipse.e4.ui.macros.IMacroAction;
-import org.eclipse.e4.ui.macros.IMacroActionProcessor;
-import org.eclipse.jface.layout.GridDataFactory;
-import org.eclipse.jface.layout.GridLayoutFactory;
-import org.eclipse.jface.viewers.ArrayContentProvider;
-import org.eclipse.jface.viewers.LabelProvider;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Layout;
-import org.eclipse.swt.widgets.Shell;
-
-/**
- * Provides a visualization on the macro recording process.
- */
-public class MacroStatusPopup extends Window {
- private GestureInterpreter interpreter;
- private List<IMacroAction> actions;
- private TableViewer viewer;
- private Label status;
-
- /** Visualize an interpreter instance */
- public static void monitor(GestureInterpreter interpreter) {
- MacroStatusPopup popup = new MacroStatusPopup(interpreter);
- interpreter.addListener(popup.listener);
- }
-
- private IMacroActionProcessor listener = new BaseProcessor() {
- @Override
- public void started() {
- open();
- }
-
- @Override
- public void finished() {
- closeWindow();
- }
-
- @Override
- public void aborted() {
- closeWindow();
- }
-
- @Override
- public void process(IMacroAction action) {
- addAction(action);
- }
- };
-
- private MacroStatusPopup(GestureInterpreter interpreter) {
- super((Shell) null);
- setShellStyle(SWT.DIALOG_TRIM | SWT.ON_TOP | SWT.RESIZE);
- setBlockOnOpen(false);
- this.interpreter = interpreter;
- }
-
- @Override
- public int open() {
- // call create() to ensure our Shell is created -- but not visible --
- // to find the Display instance so that we can restore focus
- // back to the current shell
- create();
- Shell activeShell = getShell().getDisplay().getActiveShell();
- int rc = super.open();
- if (activeShell != null) {
- activeShell.forceActive();
- }
- return rc;
- }
-
- @Override
- protected Point getInitialSize() {
- return new Point(200, 150);
- }
-
- @Override
- protected Layout getLayout() {
- return new FillLayout();
- }
-
- @Override
- protected Control createContents(final Composite container) {
- final Display display = container.getDisplay();
-
- interpreter.addIgnoreShell(container.getShell());
-
- Composite parent = new Composite(container, SWT.NONE);
- status = new Label(parent, SWT.NONE);
- viewer = new TableViewer(parent, SWT.FULL_SELECTION);
- GridDataFactory.fillDefaults().applyTo(status);
- GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getControl());
- GridLayoutFactory.fillDefaults().applyTo(parent);
-
- // poor man's button
- status.setText("FINISH");
- status.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
- status.setBackground(display.getSystemColor(SWT.COLOR_RED));
- status.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseDown(MouseEvent e) {
- finish();
- }
- });
-
- // stop recording if the window is disposed of
- container.addDisposeListener(new DisposeListener() {
- @Override
- public void widgetDisposed(DisposeEvent e) {
- finish();
- }
- });
-
- viewer.setContentProvider(new ArrayContentProvider());
- viewer.setLabelProvider(new LabelProvider());
- actions = new LinkedList<>();
- viewer.setInput(actions);
-
- return parent;
- }
-
- protected void finish() {
- interpreter.finish();
- }
-
- private void closeWindow() {
- final Shell shell = getShell();
- if (shell == null || shell.isDisposed()) {
- return;
- }
- shell.getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- close();
- }
- });
- }
-
-
- protected void addAction(final IMacroAction action) {
- final Shell shell = getShell();
- if (shell == null || shell.isDisposed()) {
- return;
- }
- // should just use databinding
- actions.add(action);
- shell.getDisplay().asyncExec(new Runnable() {
- public void run() {
- if (shell != null && !shell.isDisposed()) {
- viewer.refresh();
- // scroll to bottom
- int count = viewer.getTable().getItemCount();
- viewer.getTable().showItem(viewer.getTable().getItem(count - 1));
- }
- }
- });
- }
-
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ReplayMacroHandler.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ReplayMacroHandler.java
deleted file mode 100644
index ee9fb8b..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ReplayMacroHandler.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros;
-
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.e4.core.contexts.ContextInjectionFactory;
-import org.eclipse.e4.core.contexts.IEclipseContext;
-import org.eclipse.e4.core.di.annotations.CanExecute;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.core.di.annotations.Optional;
-import org.eclipse.e4.ui.macros.IMacroHook;
-import org.eclipse.e4.ui.macros.IMacroHook.Mode;
-import org.eclipse.e4.ui.model.application.MApplication;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-import org.osgi.framework.FrameworkUtil;
-
-public class ReplayMacroHandler {
- private static String pluginId = FrameworkUtil.getBundle(ToggleRecordingHandler.class).getSymbolicName();
-
- @CanExecute
- public boolean canExecute(MApplication application) {
- // if we have hooks then a macro recording or replay is in progress
- return application.getTransientData().get(MacroHooksManager.class.getName()) == null;
- }
-
- @Execute
- public void execute(MApplication application, Display display, @Optional Event triggeringEvent) {
- IEclipseContext context = application.getContext();
- assert context != null; // still not certain if this is required
-
- waitForModifiers(display, triggeringEvent);
-
- ApplicationMacroPlayer player = ContextInjectionFactory.make(ApplicationMacroPlayer.class, context);
- IStatus rc = runStartHooks(application, IMacroHook.Mode.PLAYBACK);
- try {
- if (rc.isOK()) {
- player.replay();
- } else {
- System.err.println("Playback aborted: " + rc);
- }
- } finally {
- runFinishHooks(application, IMacroHook.Mode.PLAYBACK);
- }
- }
-
- /**
- * The triggering event is likely a KeyDown event; wait for any modifier
- * keys to be released
- * @param display
- * @param triggeringEvent (may be null)
- */
- private void waitForModifiers(Display display, Event triggeringEvent) {
- if (triggeringEvent == null || (triggeringEvent.type != SWT.KeyUp && triggeringEvent.type != SWT.KeyDown)
- || (triggeringEvent.type == SWT.KeyDown
- && ((triggeringEvent.stateMask | triggeringEvent.keyCode) & SWT.MODIFIER_MASK) == 0)
- || (triggeringEvent.type == SWT.KeyUp
- && (triggeringEvent.stateMask & ~(triggeringEvent.keyCode & SWT.MODIFIER_MASK)) == 0)) {
- return;
- }
- final boolean ready[] = { false };
- Listener keyUpListener = new Listener() {
- @Override
- public void handleEvent(Event event) {
- // stateMask has the modifiers *prior* to this KeyUp so, providing
- // this keyCode is a modifier, we need to remove it
- int stateMask = event.stateMask & ~(event.keyCode & SWT.MODIFIER_MASK);
- ready[0] = stateMask == 0;
- }
- };
-
- // Wait for the keyboard modifiers to be released
- display.addFilter(SWT.KeyUp, keyUpListener);
- while (!ready[0] && !display.isDisposed()) {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- }
- display.removeFilter(SWT.KeyUp, keyUpListener);
- }
-
- private IStatus runStartHooks(MApplication application, Mode mode) {
- MacroHooksManager mgr = (MacroHooksManager) application.getTransientData()
- .get(MacroHooksManager.class.getName());
- if (mgr != null) {
- return new Status(IStatus.ERROR, pluginId, "Macro already in progress");
- }
- mgr = ContextInjectionFactory.make(MacroHooksManager.class, application.getContext());
- application.getTransientData().put(MacroHooksManager.class.getName(), mgr);
- return mgr.runStartHooks(mode);
- }
-
- private IStatus runFinishHooks(MApplication application, Mode mode) {
- MacroHooksManager mgr = (MacroHooksManager) application.getTransientData()
- .remove(MacroHooksManager.class.getName());
- if (mgr == null) {
- return new Status(IStatus.ERROR, pluginId, "No macro in progress");
- }
- mgr.runFinishHooks(mode);
- return Status.OK_STATUS;
- }
-
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ToggleRecordingHandler.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ToggleRecordingHandler.java
deleted file mode 100644
index f5e0cb7..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/ToggleRecordingHandler.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros;
-
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.e4.core.contexts.ContextInjectionFactory;
-import org.eclipse.e4.core.contexts.IEclipseContext;
-import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.macros.BaseProcessor;
-import org.eclipse.e4.ui.macros.IMacroActionProcessor;
-import org.eclipse.e4.ui.macros.IMacroHook;
-import org.eclipse.e4.ui.macros.IMacroHook.Mode;
-import org.eclipse.e4.ui.model.application.MApplication;
-import org.osgi.framework.FrameworkUtil;
-
-public class ToggleRecordingHandler {
- private static String pluginId = FrameworkUtil.getBundle(ToggleRecordingHandler.class).getSymbolicName();
-
- @Execute
- public void execute(MApplication application) {
- IEclipseContext context = application.getContext();
- assert context != null;
- GestureInterpreter interpreter = context.get(GestureInterpreter.class);
- if (interpreter == null) {
- // start recording
- interpreter = ContextInjectionFactory.make(GestureInterpreter.class, context);
-
- IMacroActionProcessor recorder = ContextInjectionFactory.make(ApplicationMacroRecorder.class, context);
- // interpreter.addListener(recorder);
-
- DebuggingProcessor debugging = ContextInjectionFactory.make(DebuggingProcessor.class, context);
- debugging.setDelegateRecorder(recorder);
- interpreter.addListener(debugging);
-
- openMacroWindow(interpreter, application);
- start(interpreter, application);
- } else {
- finish(interpreter, application);
- }
- }
-
- private void start(GestureInterpreter interpreter, final MApplication application) {
- IStatus rc = runStartHooks(application, IMacroHook.Mode.RECORDING);
- if (!rc.isOK()) {
- runFinishHooks(application, IMacroHook.Mode.RECORDING);
- } else {
- interpreter.addListener(new BaseProcessor() {
- @Override
- public void finished() {
- runFinishHooks(application, IMacroHook.Mode.RECORDING);
- }
-
- @Override
- public void aborted() {
- runFinishHooks(application, IMacroHook.Mode.RECORDING);
- }
- });
- interpreter.start();
- }
- }
-
- private void finish(GestureInterpreter interpreter, MApplication application) {
- interpreter.finish();
- }
-
- private void openMacroWindow(final GestureInterpreter interpreter, final MApplication application) {
- MacroStatusPopup.monitor(interpreter);
- }
-
- // should probably be moved outside of the handlers
- private IStatus runStartHooks(MApplication application, Mode mode) {
- MacroHooksManager mgr = (MacroHooksManager) application.getTransientData()
- .get(MacroHooksManager.class.getName());
- if (mgr != null) {
- return new Status(IStatus.ERROR, pluginId, "Macro already in progress");
- }
- mgr = ContextInjectionFactory.make(MacroHooksManager.class, application.getContext());
- application.getTransientData().put(MacroHooksManager.class.getName(), mgr);
- return mgr.runStartHooks(mode);
- }
-
- private IStatus runFinishHooks(MApplication application, Mode mode) {
- MacroHooksManager mgr = (MacroHooksManager) application.getTransientData()
- .remove(MacroHooksManager.class.getName());
- if (mgr == null) {
- return new Status(IStatus.ERROR, pluginId, "No macro in progress");
- }
- mgr.runFinishHooks(mode);
- return Status.OK_STATUS;
- }
-
-
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/InsertKeyStroke.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/InsertKeyStroke.java
deleted file mode 100644
index 39a9e47..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/InsertKeyStroke.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros.actions;
-
-import org.eclipse.e4.ui.macros.IMacroAction;
-import org.eclipse.jface.bindings.keys.SWTKeySupport;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Widget;
-
-/**
- * Keyboard macro performed some key stroke
- */
-public class InsertKeyStroke implements IMacroAction {
- private static int[] stateKeyCodes = { SWT.MOD1, SWT.MOD2, SWT.MOD3, SWT.MOD4 };
- private char character;
- private int stateMask;
- private int keyCode;
-
- public InsertKeyStroke(Event event, Widget widget) {
- this.character = event.character;
- this.stateMask = event.stateMask;
- this.keyCode = event.keyCode;
- }
-
- @Override
- public ReplayState process(Event e) {
- postKeyStroke(e.display);
- return ReplayState.NEXT;
- }
-
- private void postKeyStroke(final Display display) {
- Event event;
- for (int i = 0; i < stateKeyCodes.length; i++) {
- if (stateKeyCodes[i] > 0 && (stateMask & stateKeyCodes[i]) != 0) {
- event = new Event();
- event.type = SWT.KeyDown;
- event.keyCode = stateKeyCodes[i];
- display.post(event);
- }
- }
- event = new Event();
- event.type = SWT.KeyDown;
- event.character = character;
- event.keyCode = keyCode;
- display.post(event);
-
- event = new Event();
- event.type = SWT.KeyUp;
- event.character = character;
- event.keyCode = keyCode;
- display.post(event);
-
- for (int i = 0; i < stateKeyCodes.length; i++) {
- if (stateKeyCodes[i] > 0 && (stateMask & stateKeyCodes[i]) != 0) {
- event = new Event();
- event.type = SWT.KeyUp;
- event.keyCode = stateKeyCodes[i];
- display.post(event);
- }
- }
- }
-
- @Override
- public String toString() {
- return "Key " + SWTKeySupport.getKeyFormatterForPlatform().format(keyCode);
- }
-
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/InvokeCommand.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/InvokeCommand.java
deleted file mode 100644
index 544efdc..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/InvokeCommand.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros.actions;
-
-import org.eclipse.core.commands.ParameterizedCommand;
-import org.eclipse.e4.core.commands.EHandlerService;
-import org.eclipse.e4.ui.macros.IMacroAction;
-import org.eclipse.swt.widgets.Event;
-
-/**
- * Keyboard macro invoked an Eclipse-level command.
- */
-public class InvokeCommand implements IMacroAction {
- private EHandlerService handlerService;
- private ParameterizedCommand command;
-
- public InvokeCommand(EHandlerService hs, ParameterizedCommand command) {
- this.handlerService = hs;
- this.command = command;
- }
-
- @Override
- public ReplayState process(Event e) {
- if (!handlerService.canExecute(command)) {
- return ReplayState.ABORT;
- }
- handlerService.executeHandler(command);
- return ReplayState.NEXT;
- }
-
- @Override
- public String toString() {
- return "Invoke " + command.getId();
- }
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/WaitForShellActivation.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/WaitForShellActivation.java
deleted file mode 100644
index 89b7bb6..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/WaitForShellActivation.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros.actions;
-
-import org.eclipse.e4.ui.macros.IMacroAction;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Widget;
-
-public class WaitForShellActivation implements IMacroAction {
- public WaitForShellActivation(Widget widget) {
- // FIXME: store identifying information for the widget shell details?
- }
-
- @Override
- public ReplayState process(Event e) {
- // if (e.type == SWT.Activate && e.widget.getClass() == Shell.class) {
- // return ReplayState.NEXT;
- // }
- // return ReplayState.WAITING;
-
- return ReplayState.NEXT;
- }
-
- public String toString() {
- return "Wait for shell activation";
- }
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/WaitForWidgetFocus.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/WaitForWidgetFocus.java
deleted file mode 100644
index c341d3b..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/internal/macros/actions/WaitForWidgetFocus.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.internal.macros.actions;
-
-import org.eclipse.e4.ui.macros.IMacroAction;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Widget;
-
-public class WaitForWidgetFocus implements IMacroAction {
- private Class<? extends Widget> widgetClass;
-
- public WaitForWidgetFocus(Widget widget) {
- this.widgetClass = widget.getClass();
- }
-
- @Override
- public ReplayState process(Event e) {
- Control focus = e.display.getFocusControl();
- if (focus != null && focus.getClass() == widgetClass) {
- return ReplayState.NEXT;
- } else if (e.type == SWT.FocusIn && e.widget.getClass() == widgetClass) {
- return ReplayState.NEXT;
- }
- return ReplayState.WAITING;
- }
-
- public String toString() {
- return "Wait for focus onto " + widgetClass.getName();
- }
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/Activator.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/Activator.java
new file mode 100644
index 0000000..9c7cc18
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/Activator.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+@SuppressWarnings("javadoc")
+public class Activator extends AbstractUIPlugin {
+
+ private static Activator plugin;
+
+ public Activator() {
+ super();
+ plugin = this;
+ }
+
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ public static ImageDescriptor getImageDescriptor(String key) {
+ return getDefault().getImageRegistry().getDescriptor(key);
+ }
+
+ public static void log(Throwable exception) {
+ try {
+ if (plugin != null) {
+ plugin.getLog().log(new Status(IStatus.ERROR, plugin.getBundle().getSymbolicName(),
+ exception.getMessage(), exception));
+ } else {
+ // The plugin is not available. Just print to stderr.
+ exception.printStackTrace();
+ }
+ } catch (Exception e) {
+ // Print the original error if something happened, not the one
+ // related to the log not working.
+ exception.printStackTrace();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/BaseProcessor.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/BaseProcessor.java
deleted file mode 100644
index faad601..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/BaseProcessor.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.macros;
-
-/** A processor that does nothing */
-public class BaseProcessor implements IMacroActionProcessor {
-
- @Override
- public void started() {
- }
-
- @Override
- public void process(IMacroAction action) {
- }
-
- @Override
- public void finished() {
- }
-
- @Override
- public void aborted() {
- }
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/IMacroAction.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/IMacroAction.java
deleted file mode 100644
index 33beb02..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/IMacroAction.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.macros;
-
-import org.eclipse.swt.widgets.Event;
-
-public interface IMacroAction {
- /** The state of this action after processing an event */
- public enum ReplayState {
- /** This event has not changed the state of this action */
- WAITING,
-
- /**
- * This event is not compatible with this action; the macro should be
- * aborted
- */
- ABORT,
-
- /**
- * This event has been processed and the macro should move to the next
- * action
- */
- NEXT
- };
-
- public ReplayState process(Event e);
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/IMacroActionProcessor.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/IMacroActionProcessor.java
deleted file mode 100644
index 19b1192..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/IMacroActionProcessor.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.macros;
-
-/**
- * A party interested in receiving macro actions (e.g., to record them for
- * playback, or providing a UI for visualizing the status). The idea behind the
- * {@link IMacroActionProcessor}s was that there could could be intermediates that coalesce
- * some of these actions, but it hasn't proven necessary so far.
- */
-public interface IMacroActionProcessor {
-
- /** A macro recording has begun */
- void started();
-
- /** The macro recording has finished */
- void finished();
-
- /** The macro recording has been aborted */
- void aborted();
-
- /** An action occurred during the macro */
- void process(IMacroAction action);
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/IMacroHook.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/IMacroHook.java
deleted file mode 100644
index fa4e0ac..0000000
--- a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/IMacroHook.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 Manumitting Technologies Inc and others
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Manumitting Technologies - initial API and implementation
- *******************************************************************************/
-package org.eclipse.e4.ui.macros;
-
-import org.eclipse.core.runtime.IStatus;
-
-/**
- * A hook is notified before and after a macro is recorded or re-played. They
- * are typically used to disable non-deterministic behaviours in the UI (i.e.,
- * where the results or ordering of results may change on subsequent
- * re-invocations). These hooks are configured with the
- * <code>org.eclipse.e4.ui.macros.hooks</code> extension point.
- *
- * <p>
- * The macro system guarantees:
- * </p>
- * <ol>
- * <li>An instance that receives {{@link #start(Mode)} will receive a
- * corresponding {@link #stop(Mode)}.</li>
- * <li>The same instance that receives {{@link #start(Mode)} will receive
- * {@link #stop(Mode)}.</li>
- * </ol>
- */
-public interface IMacroHook {
- enum Mode {
- /** A macro is about to be or finished being recorded */
- RECORDING,
-
- /** A macro is about to be or finished being replayed */
- PLAYBACK
- };
-
- /**
- * Prepare for a macro to be recorded or played-back. Returns a status
- * object; if not OK then the macro will be aborted.
- *
- * @param mode
- * the macro mode
- * @return the status
- */
- IStatus start(Mode mode);
-
- /**
- * The macro recording or playback has been completed (perhaps successfully
- * but also may have been aborted).
- *
- * @param mode
- * the macro mode
- */
- void stop(Mode mode);
-}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/EditorUtils.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/EditorUtils.java
new file mode 100644
index 0000000..8a80cb9
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/EditorUtils.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal;
+
+import org.eclipse.e4.core.macros.IMacroContext;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Utilities related to getting/storing the current editor from/to the macro
+ * context.
+ */
+public class EditorUtils {
+
+ /**
+ * A variable which holds the current editor when macro record or playback
+ * started.
+ */
+ private final static String TARGET_STYLED_TEXT = "TARGET_STYLED_TEXT"; //$NON-NLS-1$
+
+ /**
+ * A variable which holds the current editor part when macro record or playback
+ * started.
+ */
+ private final static String TARGET_EDITOR_PART = "TARGET_EDITOR_PART"; //$NON-NLS-1$
+
+ /**
+ * @return the StyledText related to the current editor or null if there's no
+ * such widget available (i.e.: if the current editor is not a text
+ * editor or if there's no open editor).
+ */
+ public static StyledText getActiveStyledText() {
+ IEditorPart activeEditor = getActiveEditorPart();
+ if (activeEditor == null) {
+ return null;
+ }
+ return getEditorPartStyledText(activeEditor);
+ }
+
+ public static IEditorPart getActiveEditorPart() {
+ IWorkbenchWindow activeWorkbenchWindow = getActivateWorkbenchWindow();
+ if (activeWorkbenchWindow == null) {
+ return null;
+ }
+ IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage();
+ if (activePage == null) {
+ return null;
+ }
+ return activePage.getActiveEditor();
+ }
+
+ /**
+ * @return the currently active workbench window or null if not available.
+ */
+ public static IWorkbenchWindow getActivateWorkbenchWindow() {
+ IWorkbench workbench;
+ try {
+ workbench = PlatformUI.getWorkbench();
+ } catch (IllegalStateException e) { // java.lang.IllegalStateException: Workbench has not been created yet.
+ return null;
+ }
+ return workbench.getActiveWorkbenchWindow();
+ }
+
+ /**
+ * @param editor
+ * the editor for which we want the StyledText.
+ * @return the StyledText related to the current editor or null if it doesn't
+ * have a StyledText.
+ */
+ public static StyledText getEditorPartStyledText(IEditorPart editor) {
+ Control control = editor.getAdapter(Control.class);
+ StyledText styledText = null;
+ if (control instanceof StyledText) {
+ styledText = (StyledText) control;
+ }
+ return styledText;
+ }
+
+ /**
+ * Caches the current styled text as being the one active in the passed macro
+ * context.
+ *
+ * @param macroContext
+ * the macro context where it should be set.
+ */
+ public static void cacheTargetStyledText(IMacroContext macroContext) {
+ if (macroContext != null) {
+ Object object = macroContext.get(TARGET_STYLED_TEXT);
+ if (object == null) {
+ macroContext.set(TARGET_STYLED_TEXT, getActiveStyledText());
+ }
+ }
+ }
+
+ /**
+ * Caches the current editor part as being the one active in the passed macro
+ * context.
+ *
+ * @param macroContext
+ * the macro context where it should be set.
+ */
+ public static void cacheTargetEditorPart(IMacroContext macroContext) {
+ if (macroContext != null) {
+ Object object = macroContext.get(TARGET_EDITOR_PART);
+ if (object == null) {
+ macroContext.set(TARGET_EDITOR_PART, getActiveEditorPart());
+ }
+ }
+ }
+
+
+ /**
+ * Gets the styled text which was set as the current when the macro context was
+ * created.
+ *
+ * @param macroContext
+ * the macro context.
+ * @return the StyledText which was current when the recording started or null
+ * if there was no StyledText active when recording started.
+ */
+ public static StyledText getTargetStyledText(IMacroContext macroContext) {
+ if (macroContext != null) {
+ Object object = macroContext.get(TARGET_STYLED_TEXT);
+ if (object instanceof StyledText) {
+ return (StyledText) object;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the editor part which was set as the current when the macro context was
+ * created.
+ *
+ * @param macroContext
+ * the macro context.
+ * @return the editor part which was current when the recording started or null
+ * if there was no editor part active when the context was created.
+ */
+ public static IEditorPart getTargetEditorPart(IMacroContext macroContext) {
+ if (macroContext != null) {
+ Object object = macroContext.get(TARGET_EDITOR_PART);
+ if (object instanceof IEditorPart) {
+ return (IEditorPart) object;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/Messages.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/Messages.java
new file mode 100644
index 0000000..e6c8dcc
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/Messages.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ *
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.e4.ui.macros.internal.messages"; //$NON-NLS-1$
+ public static String Activator_ErrorMacroRecording;
+ public static String UserNotifications_DontShowAgain;
+ public static String UserNotifications_EditorChangedMessage;
+ public static String UserNotifications_EditorChangedTitle;
+ public static String UserNotifications_FindReplaceDialogMessage;
+ public static String UserNotifications_FindReplaceDialogTitle;
+ public static String UserNotifications_NoEditorForPlaybackMsg;
+ public static String UserNotifications_NoEditorForPlaybackTitle;
+ public static String UserNotifications_NoEditorForRecordMsg;
+ public static String UserNotifications_NoEditorForRecordTitle;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/UserNotifications.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/UserNotifications.java
new file mode 100644
index 0000000..68bfa4c
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/UserNotifications.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.ui.macros.Activator;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Helper class to show notifications to the user.
+ */
+public class UserNotifications {
+
+ private static final String FIND_REPLACE_USER_NOTIFICATION_MSG = "FIND_REPLACE_USER_NOTIFICATION_MSG"; //$NON-NLS-1$
+
+ private static final String CURRENT_EDITOR_NOTIFICATION_MSG = "CURRENT_EDITOR_NOTIFICATION_MSG"; //$NON-NLS-1$
+
+ private static final String NO_EDITOR_ON_MACRO_RECORD_STARTUP_NOTIFICATION_MSG = "NO_EDITOR_ON_MACRO_RECORD_STARTUP_NOTIFICATION_MSG"; //$NON-NLS-1$
+
+ /**
+ * Sets a given message to be shown to the user.
+ *
+ * @param message
+ * the message to be shown or null to clear it.
+ */
+ public static void setMessage(String message) {
+ IStatusLineManager statusLineManager = UserNotifications.getStatusLineManager();
+ if (statusLineManager != null) {
+ statusLineManager.setMessage(message);
+ if (message == null) {
+ // Also clear any previous error message we might have set.
+ statusLineManager.setErrorMessage(null);
+ }
+ }
+ }
+
+ /**
+ * Shows some error message related to the macro to the user.
+ *
+ * @param message
+ * the error message to be shown (cannot be null).
+ */
+ public static void showErrorMessage(String message) {
+ Activator plugin = Activator.getDefault();
+ if (plugin != null) {
+ // Log it
+ plugin.getLog().log(new Status(IStatus.INFO, plugin.getBundle().getSymbolicName(), message));
+ }
+
+ // Make it visible to the user.
+ IStatusLineManager statusLineManager = UserNotifications.getStatusLineManager();
+ if (statusLineManager == null) {
+ Shell parent = UserNotifications.getParent();
+ if (parent == null) {
+ System.err.println(Messages.Activator_ErrorMacroRecording + ": " + message); //$NON-NLS-1$
+ } else {
+ MessageDialog.openWarning(parent, Messages.Activator_ErrorMacroRecording, message);
+ }
+ } else {
+ statusLineManager.setErrorMessage(message);
+ Display current = Display.getCurrent();
+ if (current != null) {
+ // Also beep to say something strange happened.
+ current.beep();
+ }
+ }
+ }
+
+ /**
+ * @return a shell to be used as a dialog's parent.
+ */
+ private static Shell getParent() {
+ IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (activeWorkbenchWindow == null) {
+ return null;
+ }
+ return activeWorkbenchWindow.getShell();
+ }
+
+ /**
+ * @return the available status line manager for the current editor.
+ */
+ private static IStatusLineManager getStatusLineManager() {
+ IWorkbenchWindow activeWorkbenchWindow = EditorUtils.getActivateWorkbenchWindow();
+ if (activeWorkbenchWindow == null) {
+ return null;
+ }
+ IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage();
+ if (activePage == null) {
+ return null;
+ }
+ IEditorPart activeEditor = activePage.getActiveEditor();
+ if (activeEditor == null) {
+ return null;
+ }
+ IEditorSite editorSite = activeEditor.getEditorSite();
+ if (editorSite == null) {
+ return null;
+ }
+ return editorSite.getActionBars().getStatusLineManager();
+ }
+
+ /**
+ * Show a notification regarding limitations on find/replace.
+ */
+ public static void notifyFindReplace() {
+ openWarningWithIgnoreToggle(Messages.UserNotifications_FindReplaceDialogTitle,
+ Messages.UserNotifications_FindReplaceDialogMessage, FIND_REPLACE_USER_NOTIFICATION_MSG);
+ }
+
+ /**
+ * Show a notification regarding limitations on the editor changing.
+ */
+ public static void notifyCurrentEditor() {
+ openWarningWithIgnoreToggle(Messages.UserNotifications_EditorChangedTitle,
+ Messages.UserNotifications_EditorChangedMessage, CURRENT_EDITOR_NOTIFICATION_MSG);
+ }
+
+ /**
+ * Show a notification regarding not having an editor opened when record
+ * started.
+ */
+ public static void notifyNoEditorOnMacroRecordStartup() {
+ openWarningWithIgnoreToggle(Messages.UserNotifications_NoEditorForRecordTitle,
+ Messages.UserNotifications_NoEditorForRecordMsg, NO_EDITOR_ON_MACRO_RECORD_STARTUP_NOTIFICATION_MSG);
+ }
+
+ /**
+ * Show a notification regarding not having an editor opened when playback
+ * started.
+ */
+ public static void notifyNoEditorOnMacroPlaybackStartup() {
+ openWarningWithIgnoreToggle(Messages.UserNotifications_NoEditorForPlaybackTitle,
+ Messages.UserNotifications_NoEditorForPlaybackMsg, NO_EDITOR_ON_MACRO_RECORD_STARTUP_NOTIFICATION_MSG);
+ }
+
+ private static void openWarningWithIgnoreToggle(String title, String message, String key) {
+ IWorkbenchWindow activateWorkbenchWindow = EditorUtils.getActivateWorkbenchWindow();
+ if (activateWorkbenchWindow == null) {
+ return;
+ }
+ Shell shell = activateWorkbenchWindow.getShell();
+
+ IPreferenceStore store = Activator.getDefault().getPreferenceStore();
+ String val = store.getString(key);
+ if (val.trim().length() == 0) {
+ val = MessageDialogWithToggle.PROMPT; // Initial value if not specified
+ }
+
+ if (!val.equals(MessageDialogWithToggle.ALWAYS)) {
+ MessageDialogWithToggle.openWarning(shell, title, message, Messages.UserNotifications_DontShowAgain, false,
+ store, key);
+ }
+ return;
+ }
+
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/KeepMacroUIUpdated.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/KeepMacroUIUpdated.java
new file mode 100644
index 0000000..2086518
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/KeepMacroUIUpdated.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal.actions;
+
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroInstructionsListener;
+import org.eclipse.e4.core.macros.IMacroStateListener;
+import org.eclipse.e4.ui.macros.internal.UserNotifications;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+
+/**
+ * Make sure that the toolbar elements are kept properly updated even if the
+ * macro is programmatically stopped.
+ */
+public class KeepMacroUIUpdated implements IMacroStateListener {
+
+ /**
+ * A listener which will show messages to the user while he types macro
+ * instructions.
+ */
+ private static final class MacroInstructionsListener implements IMacroInstructionsListener {
+ @Override
+ public void beforeMacroInstructionAdded(IMacroInstruction macroInstruction) {
+
+ }
+
+ @Override
+ public void afterMacroInstructionAdded(IMacroInstruction macroInstruction) {
+ UserNotifications.setMessage(Messages.KeepMacroUIUpdated_RecordedInMacro + macroInstruction);
+ }
+ }
+
+ boolean wasRecording = false;
+
+ boolean wasPlayingBack = false;
+
+ IMacroInstructionsListener fMacroInstructionsListener;
+
+ @Override
+ public void macroStateChanged(EMacroService macroService, StateChange stateChange) {
+ // Update the toggle action state.
+ ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class);
+ commandService.refreshElements(ToggleMacroRecordAction.COMMAND_ID, null);
+
+ // Show a message to the user saying about the macro state.
+ if (macroService.isRecording() != wasRecording) {
+ if (!wasRecording) {
+ UserNotifications.setMessage(Messages.KeepMacroUIUpdated_StartMacroRecord);
+ } else {
+ // When we stop the record, clear the message.
+ UserNotifications.setMessage(null);
+ }
+ wasRecording = macroService.isRecording();
+ }
+ if (macroService.isPlayingBack() != wasPlayingBack) {
+ if (!wasPlayingBack) {
+ UserNotifications.setMessage(Messages.KeepMacroUIUpdated_StartMacroPlayback);
+ } else {
+ // When we stop the playback, clear the message.
+ UserNotifications.setMessage(null);
+ }
+ wasPlayingBack = macroService.isPlayingBack();
+ }
+
+ if (macroService.isRecording()) {
+ if (fMacroInstructionsListener == null) {
+ fMacroInstructionsListener = new MacroInstructionsListener();
+ macroService.addMacroInstructionsListener(fMacroInstructionsListener);
+ }
+ } else {
+ if (fMacroInstructionsListener != null) {
+ macroService.removeMacroInstructionsListener(fMacroInstructionsListener);
+ fMacroInstructionsListener = null;
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/MacroPlaybackAction.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/MacroPlaybackAction.java
new file mode 100644
index 0000000..78fd113
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/MacroPlaybackAction.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal.actions;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.e4.core.macros.Activator;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.MacroPlaybackException;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Activates the playback of the last macro.
+ */
+public class MacroPlaybackAction extends AbstractHandler {
+
+ @Override
+ public Object execute(ExecutionEvent event) {
+ try {
+ PlatformUI.getWorkbench().getService(EMacroService.class).playbackLastMacro();
+ } catch (MacroPlaybackException e) {
+ Activator.log(e);
+ IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event);
+ if (activeWorkbenchWindow != null) {
+ // When it comes from evaluating JS it adds
+ // "org.eclipse.e4.core.macros.MacroPlaybackException: "
+ // which isn't really interesting to the user (so, just remove that part).
+ String msg = e.getMessage().replace("org.eclipse.e4.core.macros.MacroPlaybackException: ", ""); //$NON-NLS-1$//$NON-NLS-2$
+ MessageDialog.openError(activeWorkbenchWindow.getShell(),
+ Messages.MacroPlaybackAction_ErrorRunningMacro, msg);
+ }
+
+ }
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/Messages.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/Messages.java
new file mode 100644
index 0000000..74df082
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/Messages.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal.actions;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ *
+ */
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.e4.ui.macros.internal.actions.messages"; //$NON-NLS-1$
+ public static String KeepMacroUIUpdated_RecordedInMacro;
+ public static String KeepMacroUIUpdated_StartMacroRecord;
+ public static String KeepMacroUIUpdated_StartMacroPlayback;
+ public static String MacroPlaybackAction_ErrorRunningMacro;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/ToggleMacroRecordAction.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/ToggleMacroRecordAction.java
new file mode 100644
index 0000000..9cecffb
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/ToggleMacroRecordAction.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal.actions;
+
+import java.util.Map;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.menus.UIElement;
+
+/**
+ * Toggles macro recording.
+ */
+public class ToggleMacroRecordAction extends AbstractHandler implements IElementUpdater {
+
+ /**
+ * The id of the toggle macro record action.
+ */
+ public static final String COMMAND_ID = "org.eclipse.e4.ui.macros.toggleRecordMacro"; //$NON-NLS-1$
+
+ @Override
+ public Object execute(ExecutionEvent event) {
+ PlatformUI.getWorkbench().getService(EMacroService.class).toggleMacroRecord();
+ return null;
+ }
+
+ @Override
+ public void updateElement(UIElement element, Map parameters) {
+ element.setChecked(PlatformUI.getWorkbench().getService(EMacroService.class).isRecording());
+ }
+
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/messages.properties b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/messages.properties
new file mode 100644
index 0000000..4566bf7
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/actions/messages.properties
@@ -0,0 +1,4 @@
+KeepMacroUIUpdated_RecordedInMacro=Recorded in macro:
+KeepMacroUIUpdated_StartMacroRecord=Started macro recording
+KeepMacroUIUpdated_StartMacroPlayback=Start macro playback
+MacroPlaybackAction_ErrorRunningMacro=Error running macro
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/CommandManagerExecutionListener.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/CommandManagerExecutionListener.java
new file mode 100644
index 0000000..ba44a3e
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/CommandManagerExecutionListener.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal.keybindings;
+
+import java.util.Stack;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IExecutionListener;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.ui.macros.Activator;
+import org.eclipse.e4.ui.macros.internal.EditorUtils;
+import org.eclipse.e4.ui.macros.internal.UserNotifications;
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * Used to record commands being executed in the current macro.
+ */
+public class CommandManagerExecutionListener implements IExecutionListener {
+
+ private final EMacroService fMacroService;
+
+ private static class ParameterizedCommandAndTrigger {
+
+ private ParameterizedCommand parameterizedCommand;
+ private Object trigger;
+
+ private ParameterizedCommandAndTrigger(ParameterizedCommand parameterizedCommand, Object trigger) {
+ this.parameterizedCommand = parameterizedCommand;
+ this.trigger = trigger;
+ }
+
+ @Override
+ public String toString() {
+ if (parameterizedCommand == null) {
+ return "parameterizedCommand == null"; //$NON-NLS-1$
+ }
+ return parameterizedCommand.getId();
+ }
+ }
+
+ /**
+ * A stack to keep information on the parameterized commands and what triggered
+ * it.
+ */
+ private final Stack<ParameterizedCommandAndTrigger> fParameterizedCommandsAndTriggerStack = new Stack<>();
+
+ /**
+ * The handler service.
+ */
+ private final EHandlerService fHandlerService;
+
+ /**
+ * @param macroService
+ * the macro service
+ * @param handlerService
+ * the handler service (used to execute actions).
+ */
+ public CommandManagerExecutionListener(EMacroService macroService, EHandlerService handlerService) {
+ this.fMacroService = macroService;
+ this.fHandlerService = handlerService;
+ }
+
+ @Override
+ public void notHandled(String commandId, NotHandledException exception) {
+ popCommand(commandId);
+ }
+
+ @Override
+ public void postExecuteFailure(String commandId, ExecutionException exception) {
+ popCommand(commandId);
+ }
+
+ private ParameterizedCommandAndTrigger popCommand(String commandId) {
+ ParameterizedCommandAndTrigger commandAndTrigger = null;
+ while (!fParameterizedCommandsAndTriggerStack.empty()) {
+ commandAndTrigger = fParameterizedCommandsAndTriggerStack.pop();
+ if (commandAndTrigger != null && commandAndTrigger.parameterizedCommand != null) {
+ if (commandId.equals(commandAndTrigger.parameterizedCommand.getCommand().getId())) {
+ return commandAndTrigger;
+ }
+ }
+ }
+ if (commandAndTrigger != null) {
+ Activator.log(new RuntimeException(
+ String.format("Expected to find %s in parameterizedCommand stack. Found: %s", commandId, //$NON-NLS-1$
+ commandAndTrigger)));
+ }
+ return null;
+ }
+
+ @Override
+ public void postExecuteSuccess(String commandId, Object returnValue) {
+ ParameterizedCommandAndTrigger commandAndTrigger = popCommand(commandId);
+ if (commandAndTrigger == null) {
+ // Can happen if we didn't get the preExecute (i.e.: the toggle
+ // macro record is executed and post executed only (the pre execute
+ // is skipped because recording still wasn't in place).
+ //
+ // Another reason could be that it was an event generated for another
+ // editor, not the one we should recording.
+ return;
+ }
+ if (fMacroService.isRecording()) {
+ // Record it if needed.
+ if (fMacroService.getRecordCommandInMacro(commandId)) {
+ if (commandAndTrigger.trigger instanceof Event) {
+ Event swtEvent = (Event) commandAndTrigger.trigger;
+ // Only record commands executed in the initial editor.
+ if (fFilter.acceptEvent(swtEvent)) {
+ fMacroService.addMacroInstruction(new MacroInstructionForParameterizedCommand(
+ commandAndTrigger.parameterizedCommand, swtEvent, this.fHandlerService));
+ }
+ } else {
+ fMacroService.addMacroInstruction(new MacroInstructionForParameterizedCommand(
+ commandAndTrigger.parameterizedCommand, this.fHandlerService));
+ }
+ }
+ }
+ }
+
+ @Override
+ public void preExecute(String commandId, ExecutionEvent event) {
+ if (acceptEvent(event)) {
+ if ("org.eclipse.ui.edit.findReplace".equals(commandId)) { //$NON-NLS-1$
+ // We can't deal with find/replace at this point. Let the user know.
+ UserNotifications.notifyFindReplace();
+ }
+ }
+ // Let's check if it should actually be recorded.
+ if (fMacroService.getRecordCommandInMacro(commandId)) {
+ if (!acceptEvent(event)) {
+ fParameterizedCommandsAndTriggerStack.add(null);
+ return;
+ }
+ ParameterizedCommand command = ParameterizedCommand.generateCommand(event.getCommand(),
+ event.getParameters());
+ fParameterizedCommandsAndTriggerStack.add(new ParameterizedCommandAndTrigger(command, event.getTrigger()));
+ }
+ }
+
+ /**
+ * Filter to accept or reject an event (accepting means we can generate a macro
+ * instruction for it and false means we shouldn't).
+ */
+ public static interface IFilter {
+
+ /**
+ * @param swtEvent
+ * @return true if the given swtEvent should be accepted.
+ */
+ boolean acceptEvent(Event swtEvent);
+ }
+
+ private boolean acceptEvent(ExecutionEvent event) {
+ Object trigger = event.getTrigger();
+ if (trigger instanceof Event) {
+ Event swtEvent = (Event) trigger;
+ return fFilter.acceptEvent(swtEvent);
+ }
+ return true;
+ }
+
+ /**
+ * Note that it's private and shouldn't be usually changed, although the current
+ * structure is helpful as it allows us to accept any event on tests through
+ * reflection.
+ */
+ private IFilter fFilter = new IFilter() {
+
+ @Override
+ public boolean acceptEvent(Event swtEvent) {
+ if (EditorUtils.getActiveStyledText() != EditorUtils
+ .getTargetStyledText(fMacroService.getMacroRecordContext())) {
+ // Note: it previously checked swtEvent.widget, but sometimes the event was
+ // generated from the wrong control (i.e.: opening a new editor and doing
+ // some action sometimes had the widget from a different editor).
+ return false;
+ }
+ return true;
+ }
+ };
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/CommandManagerExecutionListenerInstaller.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/CommandManagerExecutionListenerInstaller.java
new file mode 100644
index 0000000..073654f
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/CommandManagerExecutionListenerInstaller.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal.keybindings;
+
+import javax.inject.Inject;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.IMacroRecordContext;
+import org.eclipse.e4.core.macros.IMacroStateListener;
+import org.eclipse.e4.core.macros.IMacroStateListener1;
+import org.eclipse.e4.ui.macros.internal.EditorUtils;
+
+/**
+ * A macro state listener that will install the execution listener when in a
+ * record context.
+ */
+public class CommandManagerExecutionListenerInstaller implements IMacroStateListener, IMacroStateListener1 {
+
+ @Inject
+ private CommandManager fCommandManager;
+
+ @Inject
+ private EHandlerService fHandlerService;
+
+ private CommandManagerExecutionListener fCommandManagerExecutionListener;
+
+ public CommandManagerExecutionListener getCommandManagerExecutionListener() {
+ return fCommandManagerExecutionListener;
+ }
+
+ @Override
+ public void macroStateChanged(EMacroService macroService, StateChange stateChange) {
+ if (macroService.isRecording()) {
+ if (fCommandManagerExecutionListener == null) {
+ fCommandManagerExecutionListener = new CommandManagerExecutionListener(macroService, fHandlerService);
+ fCommandManager.addExecutionListener(fCommandManagerExecutionListener);
+ }
+ } else {
+ if (fCommandManagerExecutionListener != null) {
+ fCommandManager.removeExecutionListener(fCommandManagerExecutionListener);
+ fCommandManagerExecutionListener = null;
+ }
+ }
+ }
+
+ @Override
+ public void onMacroPlaybackContextCreated(IMacroPlaybackContext macroContext) {
+ EditorUtils.cacheTargetStyledText(macroContext);
+ }
+
+ @Override
+ public void onMacroRecordContextCreated(IMacroRecordContext macroContext) {
+ EditorUtils.cacheTargetStyledText(macroContext);
+ }
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/MacroInstructionForParameterizedCommand.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/MacroInstructionForParameterizedCommand.java
new file mode 100644
index 0000000..1cc0213
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/MacroInstructionForParameterizedCommand.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal.keybindings;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.macros.Activator;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.MacroPlaybackException;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * A macro instruction for parameterized commands.
+ */
+public class MacroInstructionForParameterizedCommand implements IMacroInstruction {
+
+ private static final String ID = "Command"; //$NON-NLS-1$
+
+ private static final String CHARACTER = "character"; //$NON-NLS-1$
+
+ private static final String TYPE = "type"; //$NON-NLS-1$
+
+ private static final String STATE_MASK = "stateMask"; //$NON-NLS-1$
+
+ private static final String KEY_CODE = "keyCode"; //$NON-NLS-1$
+
+ private static final String COMMAND = "command"; //$NON-NLS-1$
+
+ private static final String NO_EVENT = "no_event"; //$NON-NLS-1$
+
+ private EHandlerService fHandlerService;
+
+ private ParameterizedCommand fCmd;
+
+ private Event fEvent;
+
+ public MacroInstructionForParameterizedCommand(ParameterizedCommand cmd, EHandlerService handlerService) {
+ this.fCmd = cmd;
+ this.fHandlerService = handlerService;
+ }
+
+ /**
+ * @param cmd
+ * the command recorded.
+ * @param event
+ * the related event.
+ * @param keybindingDispatcher
+ * the dispatcher to be used to execute commands.
+ */
+ public MacroInstructionForParameterizedCommand(ParameterizedCommand cmd, Event event,
+ EHandlerService keybindingDispatcher) {
+ this(cmd, keybindingDispatcher);
+
+ // Create a new event (we want to make sure that only the given info is
+ // really needed on playback and don't want to keep a reference to the
+ // original widget).
+ Event newEvent = new Event();
+ newEvent.keyCode = event.keyCode;
+ newEvent.stateMask = event.stateMask;
+ newEvent.type = event.type;
+ newEvent.character = event.character;
+
+ this.fEvent = newEvent;
+ }
+
+ @Override
+ public void execute(IMacroPlaybackContext macroPlaybackContext) throws MacroPlaybackException {
+ ParameterizedCommand cmd = fCmd;
+ if (cmd == null) {
+ throw new MacroPlaybackException("Parameterized command not set."); //$NON-NLS-1$
+ }
+ final EHandlerService handlerService = fHandlerService;
+ final Command command = cmd.getCommand();
+
+ final IEclipseContext staticContext = EclipseContextFactory.create("keys-staticContext"); //$NON-NLS-1$
+ staticContext.set(Event.class, this.fEvent);
+
+ if (!command.isDefined()) {
+ throw new MacroPlaybackException(
+ String.format("Command: %s not defined (unable to playback macro).", cmd.getId())); //$NON-NLS-1$
+ }
+
+ try {
+ boolean commandEnabled = handlerService.canExecute(cmd, staticContext);
+ if (!commandEnabled) {
+ // This is to handle the following case:
+ // 1. Open an editor and record keypresses and an undo
+ // 2. Close editor/Open editor
+ // 3. Playback macro: at this point, the undo action is actually
+ // disabled, so, we need to process the current events in the
+ // queue and wait for it to be enabled (or fail if it can't be
+ // enabled in the current situation).
+ for (int i = 0; i < 100; i++) {
+ Display.getCurrent().readAndDispatch();
+ commandEnabled = handlerService.canExecute(cmd, staticContext);
+ if (commandEnabled) {
+ break;
+ }
+ }
+ commandEnabled = handlerService.canExecute(cmd, staticContext);
+ if (!commandEnabled) {
+ String name;
+ try {
+ name = cmd.getName();
+ } catch (NotDefinedException e) {
+ name = Messages.MacroInstructionForParameterizedCommand_CommandUnknown;
+ }
+ throw new MacroPlaybackException(
+ String.format(Messages.MacroInstructionForParameterizedCommand_CommandNotEnabled, name, cmd.getId()));
+ }
+ }
+
+ handlerService.executeHandler(cmd, staticContext);
+ final Object commandException = staticContext.get(HandlerServiceImpl.HANDLER_EXCEPTION);
+ if (commandException instanceof Exception) {
+ Activator.log((Exception) commandException);
+ }
+
+ } finally {
+ staticContext.dispose();
+ }
+ }
+
+ @Override
+ public String getId() {
+ return ID;
+ }
+
+ @Override
+ public String toString() {
+ try {
+ return String.format(Messages.MacroInstructionForParameterizedCommand_0, this.fCmd.getName());
+ } catch (NotDefinedException e) {
+ return String.format(Messages.MacroInstructionForParameterizedCommand_0, "Undefined"); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public Map<String, String> toMap() {
+ Map<String, String> map = new HashMap<>();
+ String serialized = fCmd.serialize();
+ Assert.isNotNull(serialized);
+ map.put(COMMAND, serialized);
+ if (this.fEvent == null) {
+ map.put(NO_EVENT, NO_EVENT);
+ }
+ map.put(KEY_CODE, Integer.toString(fEvent.keyCode));
+ map.put(STATE_MASK, Integer.toString(fEvent.stateMask));
+ map.put(TYPE, Integer.toString(fEvent.type));
+ map.put(CHARACTER, Character.toString(fEvent.character));
+
+ return map;
+ }
+
+ /**
+ * @param map
+ * a map (created from {@link #toMap()}.
+ * @param commandManager
+ * the command manager used to deserialize commands.
+ * @param keybindingDispatcher
+ * the dispatcher for commands.
+ * @return a macro instruction created from the map (created from
+ * {@link #toMap()}.
+ * @throws Exception
+ * if it was not possible to recreate the macro instruction.
+ */
+ /* default */ static MacroInstructionForParameterizedCommand fromMap(Map<String, String> map,
+ CommandManager commandManager, EHandlerService keybindingDispatcher) throws Exception {
+ Assert.isNotNull(commandManager);
+ Assert.isNotNull(map);
+ Assert.isNotNull(keybindingDispatcher);
+ ParameterizedCommand cmd = commandManager.deserialize(map.get(COMMAND));
+ if (map.containsKey(NO_EVENT)) {
+ return new MacroInstructionForParameterizedCommand(cmd, keybindingDispatcher);
+ }
+ Event event = new Event();
+ event.keyCode = Integer.parseInt(map.get(KEY_CODE));
+ event.stateMask = Integer.parseInt(map.get(STATE_MASK));
+ event.type = Integer.parseInt(map.get(TYPE));
+ event.character = map.get(CHARACTER).charAt(0);
+ return new MacroInstructionForParameterizedCommand(cmd, event, keybindingDispatcher);
+ }
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/MacroInstructionForParameterizedCommandFactory.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/MacroInstructionForParameterizedCommandFactory.java
new file mode 100644
index 0000000..32ceb91
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/MacroInstructionForParameterizedCommandFactory.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal.keybindings;
+
+import java.util.Map;
+import javax.inject.Inject;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroInstructionFactory;
+
+/**
+ * Factory for macro instructions which were created from parameterized
+ * commands.
+ */
+public class MacroInstructionForParameterizedCommandFactory implements IMacroInstructionFactory {
+
+ @Inject
+ private CommandManager fCommandManager;
+
+ @Inject
+ private EHandlerService fHandlerService;
+
+ @Override
+ public IMacroInstruction create(Map<String, String> stringMap) throws Exception {
+ return MacroInstructionForParameterizedCommand.fromMap(stringMap, fCommandManager, fHandlerService);
+ }
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/Messages.java b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/Messages.java
new file mode 100644
index 0000000..0c3c5b8
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/Messages.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.internal.keybindings;
+
+import org.eclipse.osgi.util.NLS;
+
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.e4.ui.macros.internal.keybindings.messages"; //$NON-NLS-1$
+
+ public static String CommandManagerExecutionListener_CommandNotRecorded;
+
+ public static String KeyBindingDispatcherInterceptor_SkipExecutionOfCommand;
+
+ public static String MacroInstructionForParameterizedCommand_0;
+
+ public static String MacroInstructionForParameterizedCommand_CommandNotEnabled;
+
+ public static String MacroInstructionForParameterizedCommand_CommandUnknown;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/messages.properties b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/messages.properties
new file mode 100644
index 0000000..6991310
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/keybindings/messages.properties
@@ -0,0 +1,5 @@
+CommandManagerExecutionListener_CommandNotRecorded=Command %s executed but not recorded in macro.
+KeyBindingDispatcherInterceptor_SkipExecutionOfCommand=Stopped execution of command not whitelisted in macro: %s
+MacroInstructionForParameterizedCommand_0=Command: %s
+MacroInstructionForParameterizedCommand_CommandNotEnabled=Command "%s" (%s) not enabled.
+MacroInstructionForParameterizedCommand_CommandUnknown=Unknown
diff --git a/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/messages.properties b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/messages.properties
new file mode 100644
index 0000000..418b199
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.macros/src/org/eclipse/e4/ui/macros/internal/messages.properties
@@ -0,0 +1,10 @@
+Activator_ErrorMacroRecording=Error macro recording
+UserNotifications_DontShowAgain=Don't show this message again
+UserNotifications_EditorChangedMessage=Macro recording currently is limited to the editor which was active when macro recording started.\n\nActions done in other editors or contexts will not be recorded.
+UserNotifications_EditorChangedTitle=Editor Changed
+UserNotifications_FindReplaceDialogMessage=Macro recording is currently not integrated with the find/replace dialog.\n\nPlease use the find next and the incremental find actions through keybindings in the editor as a workaround.
+UserNotifications_FindReplaceDialogTitle=Find Replace Dialog
+UserNotifications_NoEditorForPlaybackMsg=Macro playback currently only works within the scope of a text editor. As no text editor was found to be active, no playback will take place.
+UserNotifications_NoEditorForPlaybackTitle=No Editor for Playback
+UserNotifications_NoEditorForRecordMsg=Macro recording currently only works within the scope of a text editor. As no text editor was found to be active, no actions will be recorded.
+UserNotifications_NoEditorForRecordTitle=No Editor for Record
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/.classpath b/bundles/org.eclipse.ui.workbench.texteditor.macros/.classpath
similarity index 100%
rename from bundles/org.eclipse.e4.ui.macros.jdt/.classpath
rename to bundles/org.eclipse.ui.workbench.texteditor.macros/.classpath
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/.gitignore b/bundles/org.eclipse.ui.workbench.texteditor.macros/.gitignore
new file mode 100644
index 0000000..ae3c172
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/.project b/bundles/org.eclipse.ui.workbench.texteditor.macros/.project
similarity index 63%
copy from bundles/org.eclipse.e4.ui.macros.jdt/.project
copy to bundles/org.eclipse.ui.workbench.texteditor.macros/.project
index 4babb46..8ff43ac 100644
--- a/bundles/org.eclipse.e4.ui.macros.jdt/.project
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>org.eclipse.e4.ui.macros.jdt</name>
+ <name>org.eclipse.ui.workbench.texteditor.macros</name>
<comment></comment>
<projects>
</projects>
@@ -20,9 +20,20 @@
<arguments>
</arguments>
</buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
</natures>
</projectDescription>
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.core.runtime.prefs b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..0566737
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,419 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=error
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=error
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=error
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=120
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..b058cde
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,125 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_blocks=false
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup_profile=org.eclipse.jdt.ui.default.eclipse_clean_up_profile
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=org.eclipse.jdt.ui.default.eclipse_profile
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment"/><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=true
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=false
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.pde.api.tools.prefs b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 0000000..a09ec9c
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,97 @@
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+API_USE_SCAN_FIELD_SEVERITY=Error
+API_USE_SCAN_METHOD_SEVERITY=Error
+API_USE_SCAN_TYPE_SEVERITY=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+ILLEGAL_EXTEND=Warning
+ILLEGAL_IMPLEMENT=Warning
+ILLEGAL_INSTANTIATE=Warning
+ILLEGAL_OVERRIDE=Warning
+ILLEGAL_REFERENCE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INVALID_JAVADOC_TAG=Warning
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Error
+LEAK_EXTEND=Warning
+LEAK_FIELD_DECL=Warning
+LEAK_IMPLEMENT=Warning
+LEAK_METHOD_PARAM=Warning
+LEAK_METHOD_RETURN_TYPE=Warning
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+MISSING_EE_DESCRIPTIONS=Warning
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+UNUSED_PROBLEM_FILTERS=Warning
+automatically_removed_unused_problem_filters=false
+eclipse.preferences.version=1
+incompatible_api_component_version=Error
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+invalid_since_tag_version=Error
+malformed_since_tag=Error
+missing_since_tag=Error
+report_api_breakage_when_major_version_incremented=Disabled
+report_resolution_errors_api_component=Warning
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.pde.prefs b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.pde.prefs
new file mode 100644
index 0000000..2ce5047
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/.settings/org.eclipse.pde.prefs
@@ -0,0 +1,32 @@
+compilers.f.unresolved-features=1
+compilers.f.unresolved-plugins=1
+compilers.incompatible-environment=1
+compilers.p.build=1
+compilers.p.build.bin.includes=1
+compilers.p.build.encodings=2
+compilers.p.build.java.compiler=2
+compilers.p.build.java.compliance=1
+compilers.p.build.missing.output=1
+compilers.p.build.output.library=1
+compilers.p.build.source.library=1
+compilers.p.build.src.includes=1
+compilers.p.deprecated=1
+compilers.p.discouraged-class=1
+compilers.p.internal=1
+compilers.p.missing-packages=1
+compilers.p.missing-version-export-package=2
+compilers.p.missing-version-import-package=1
+compilers.p.missing-version-require-bundle=1
+compilers.p.no-required-att=0
+compilers.p.not-externalized-att=1
+compilers.p.unknown-attribute=1
+compilers.p.unknown-class=1
+compilers.p.unknown-element=1
+compilers.p.unknown-identifier=1
+compilers.p.unknown-resource=1
+compilers.p.unresolved-ex-points=0
+compilers.p.unresolved-import=0
+compilers.s.create-docs=false
+compilers.s.doc-folder=doc
+compilers.s.open-tags=1
+eclipse.preferences.version=1
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.workbench.texteditor.macros/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..a4a1104
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/META-INF/MANIFEST.MF
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Macros for text editors
+Bundle-SymbolicName: org.eclipse.ui.workbench.texteditor.macros;singleton:=true
+Bundle-Version: 0.1.0.qualifier
+Bundle-Activator: org.eclipse.ui.workbench.texteditor.macros.Activator
+Bundle-Vendor: Eclipse.org
+Require-Bundle: org.eclipse.e4.ui.bindings;bundle-version="0.10",
+ org.eclipse.e4.ui.macros;bundle-version="0.1",
+ org.eclipse.ui.workbench;bundle-version="3.108",
+ org.eclipse.e4.core.macros,
+ org.eclipse.swt,
+ org.eclipse.osgi,
+ org.eclipse.jface.text,
+ org.eclipse.ui.workbench.texteditor,
+ org.eclipse.jface;bundle-version="3.13.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: javax.inject,
+ org.eclipse.core.runtime;version="3.5",
+ org.eclipse.e4.core.commands,
+ org.eclipse.e4.core.contexts,
+ org.eclipse.e4.core.di,
+ org.eclipse.e4.core.di.annotations,
+ org.osgi.framework;version="1.8"
+Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/build.properties b/bundles/org.eclipse.ui.workbench.texteditor.macros/build.properties
new file mode 100644
index 0000000..163cdac
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/build.properties
@@ -0,0 +1,6 @@
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ OSGI-INF/
+source.. = src/
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/plugin.xml b/bundles/org.eclipse.ui.workbench.texteditor.macros/plugin.xml
new file mode 100644
index 0000000..1e01cef
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/plugin.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin>
+
+ <extension
+ point="org.eclipse.e4.core.macros.macroStateListeners">
+ <macroStateListener
+ class="org.eclipse.ui.workbench.texteditor.macros.internal.EditorPartMacroInstaller">
+ </macroStateListener>
+ <macroStateListener
+ class="org.eclipse.ui.workbench.texteditor.macros.internal.MacroStyledTextInstaller">
+ </macroStateListener>
+ </extension>
+
+ <extension
+ point="org.eclipse.e4.core.macros.macroInstructionsFactory">
+ <macroInstructionsFactory
+ class="org.eclipse.ui.workbench.texteditor.macros.internal.StyledTextKeyDownMacroInstructionFactory"
+ macroInstructionId="KeyEvent">
+ </macroInstructionsFactory>
+ </extension>
+
+ <extension point="org.eclipse.e4.core.macros.macroCommandCustomization">
+ <customizedCommand id="org.eclipse.ui.edit.text.contentAssist.proposals" recordMacroInstruction="false"/>
+ <customizedCommand id="org.eclipse.ui.edit.text.quick_assist.proposals" recordMacroInstruction="false"/>
+ </extension>
+
+</plugin>
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/pom.xml b/bundles/org.eclipse.ui.workbench.texteditor.macros/pom.xml
new file mode 100644
index 0000000..e21249c
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2017 Fabio Zadrozny and others.
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Distribution License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/org/documents/edl-v10.php
+
+ Contributors:
+ Fabio Zadrozny - initial implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.e4.ui</groupId>
+ <artifactId>e4-ui-aggregator</artifactId>
+ <version>0.17.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+
+ <artifactId>org.eclipse.ui.workbench.texteditor.macros</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+
+ </project>
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/Activator.java b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/Activator.java
new file mode 100644
index 0000000..830103c
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/Activator.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.ui.workbench.texteditor.macros;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+@SuppressWarnings("javadoc")
+public class Activator extends AbstractUIPlugin {
+
+ private static Activator plugin;
+
+ public Activator() {
+ super();
+ plugin = this;
+ }
+
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/AbstractSWTEventMacroInstruction.java b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/AbstractSWTEventMacroInstruction.java
new file mode 100644
index 0000000..b9f89a2
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/AbstractSWTEventMacroInstruction.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.ui.workbench.texteditor.macros.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * Base class for a macro instruction based on events from a given type.
+ *
+ * Note that it doesn't store all the information on events, only character,
+ * stateMask, keyCode, keyLocation and detail (and the actual type is meant to
+ * be gotten from the class which overrides it or passed when needed).
+ *
+ * The actual fields that it stores may grow over time (and when restored, if
+ * those weren't properly saved, default values should be used).
+ */
+public abstract class AbstractSWTEventMacroInstruction implements IMacroInstruction {
+
+ private static final String CHARACTER = "character"; //$NON-NLS-1$
+
+ private static final String STATE_MASK = "stateMask"; //$NON-NLS-1$
+
+ private static final String KEY_CODE = "keyCode"; //$NON-NLS-1$
+
+ private static final String DETAIL = "detail"; //$NON-NLS-1$
+
+ private static final String KEY_LOCATION = "keyLocation"; //$NON-NLS-1$
+
+ protected final Event fEvent;
+
+ /**
+ * @param event
+ * the event for which the macro instruction is being created.
+ */
+ public AbstractSWTEventMacroInstruction(Event event) {
+ // Create a new event (we want to make sure that only the given info is
+ // really needed on playback and don't want to keep a reference to the
+ // original widget).
+ Assert.isTrue(event.type == getEventType());
+ Event newEvent = copyEvent(event);
+
+ this.fEvent = newEvent;
+ }
+
+ /**
+ *
+ * @return the event type of the events that this macro instruction is related
+ * to.
+ */
+ protected abstract int getEventType();
+
+ /**
+ * Helper to create a copy of some event.
+ *
+ * @param event
+ * the event to be copied.
+ * @return a copy of the passed event.
+ */
+ protected Event copyEvent(Event event) {
+ Event newEvent = new Event();
+ newEvent.keyCode = event.keyCode;
+ newEvent.stateMask = event.stateMask;
+ newEvent.type = event.type;
+ newEvent.character = event.character;
+ newEvent.detail = event.detail;
+ newEvent.keyLocation = event.keyLocation;
+ return newEvent;
+ }
+
+ /**
+ * Actually creates an event based on the contents previously gotten from
+ * {@link #toMap()}.
+ */
+ protected static Event createEventFromMap(Map<String, String> map, int eventType) {
+ Event event = new Event();
+ event.type = eventType;
+
+ String keyCode = map.get(KEY_CODE);
+ if (keyCode != null) {
+ event.keyCode = Integer.parseInt(keyCode);
+ } else {
+ event.keyCode = 0;
+ }
+
+ String stateMask = map.get(STATE_MASK);
+ if (stateMask != null) {
+ event.stateMask = Integer.parseInt(stateMask);
+ } else {
+ event.stateMask = 0;
+ }
+
+ String character = map.get(CHARACTER);
+ if (character != null) {
+ event.character = character.charAt(0);
+ } else {
+ event.character = '\0';
+ }
+
+ String detail = map.get(DETAIL);
+ if (detail != null) {
+ event.detail = Integer.parseInt(detail);
+ } else {
+ event.detail = 0;
+ }
+
+ String keyLocation = map.get(KEY_LOCATION);
+ if (keyLocation != null) {
+ event.keyLocation = Integer.parseInt(keyLocation);
+ } else {
+ event.keyLocation = 0;
+ }
+ return event;
+ }
+
+ @Override
+ public Map<String, String> toMap() {
+ Map<String, String> map = new HashMap<>();
+
+ // Only save non-default values.
+
+ if (fEvent.keyCode != 0) {
+ map.put(KEY_CODE, Integer.toString(fEvent.keyCode));
+ }
+
+ if (fEvent.stateMask != 0) {
+ map.put(STATE_MASK, Integer.toString(fEvent.stateMask));
+ }
+
+ if (fEvent.character != '\0') {
+ map.put(CHARACTER, Character.toString(fEvent.character));
+ }
+
+ if (fEvent.detail != 0) {
+ map.put(DETAIL, Integer.toString(fEvent.detail));
+ }
+
+ if (fEvent.keyLocation != 0) {
+ map.put(KEY_LOCATION, Integer.toString(fEvent.keyLocation));
+ }
+ return map;
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/EditorPartMacroInstaller.java b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/EditorPartMacroInstaller.java
new file mode 100644
index 0000000..885d589
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/EditorPartMacroInstaller.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.ui.workbench.texteditor.macros.internal;
+
+import org.eclipse.e4.core.macros.CancelMacroException;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.IMacroRecordContext;
+import org.eclipse.e4.core.macros.IMacroStateListener;
+
+/**
+ * A listener to the macro context which will enable notifications to the user
+ * regarding limitations of recording only in the current editor.
+ */
+public class EditorPartMacroInstaller implements IMacroStateListener {
+
+ private static final String NOTIFY_MACRO_ONLY_IN_CURRENT_EDITOR = "NOTIFY_MACRO_ONLY_IN_CURRENT_EDITOR"; //$NON-NLS-1$
+
+ @Override
+ public void macroStateChanged(EMacroService macroService, StateChange stateChange)
+ throws CancelMacroException {
+ if (stateChange == StateChange.RECORD_STARTED) {
+ IMacroRecordContext context = macroService.getMacroRecordContext();
+ NotifyMacroOnlyInCurrentEditor notifyMacroOnlyInCurrentEditor = new NotifyMacroOnlyInCurrentEditor(
+ macroService);
+ notifyMacroOnlyInCurrentEditor.checkEditorActiveForMacroRecording();
+
+ notifyMacroOnlyInCurrentEditor.install();
+ context.set(NOTIFY_MACRO_ONLY_IN_CURRENT_EDITOR, notifyMacroOnlyInCurrentEditor);
+
+ } else if (stateChange == StateChange.RECORD_FINISHED) {
+ IMacroRecordContext context = macroService.getMacroRecordContext();
+ Object object = context.get(NOTIFY_MACRO_ONLY_IN_CURRENT_EDITOR);
+ if (object instanceof NotifyMacroOnlyInCurrentEditor) {
+ NotifyMacroOnlyInCurrentEditor notifyMacroOnlyInCurrentEditor = (NotifyMacroOnlyInCurrentEditor) object;
+ notifyMacroOnlyInCurrentEditor.uninstall();
+ }
+ } else if (stateChange == StateChange.PLAYBACK_STARTED) {
+ new NotifyMacroOnlyInCurrentEditor(macroService).checkEditorActiveForMacroPlayback();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/MacroStyledTextInstaller.java b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/MacroStyledTextInstaller.java
new file mode 100644
index 0000000..d4e9e05
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/MacroStyledTextInstaller.java
@@ -0,0 +1,287 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.ui.workbench.texteditor.macros.internal;
+
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.IMacroContext;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.IMacroRecordContext;
+import org.eclipse.e4.core.macros.IMacroStateListener;
+import org.eclipse.e4.core.macros.IMacroStateListener1;
+import org.eclipse.e4.ui.macros.internal.EditorUtils;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextOperationTargetExtension;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.texteditor.ITextEditorActionConstants;
+import org.eclipse.ui.texteditor.ITextEditorExtension5;
+import org.eclipse.ui.texteditor.TextEditorAction;
+
+/**
+ * Helper class to deal with entering/exiting macro record/playback.
+ */
+public class MacroStyledTextInstaller implements IMacroStateListener, IMacroStateListener1 {
+
+ /**
+ * Constant used to keep memento on the macro context.
+ */
+ private static final String MACRO_STYLED_TEXT_INSTALLER_MEMENTO = "MACRO_STYLED_TEXT_INSTALLER_MEMENTO"; //$NON-NLS-1$
+
+ /**
+ * Constant used to keep macro recorder on the macro context.
+ */
+ private static final String MACRO_STYLED_TEXT_INSTALLER_MACRO_RECORDER = "MACRO_STYLED_TEXT_INSTALLER_MACRO_RECORDER"; //$NON-NLS-1$
+
+ /**
+ * Constant used to save whether the content assist was enabled before being
+ * disabled in disableCodeCompletion.
+ */
+ private static final String CONTENT_ASSIST_ENABLED = "contentAssistEnabled";//$NON-NLS-1$
+
+ /**
+ * Constant used to save whether the quick assist was enabled before being
+ * disabled in disableCodeCompletion.
+ */
+ private static final String QUICK_ASSIST_ENABLED = "quickAssistEnabled";//$NON-NLS-1$
+
+ /**
+ * Re-enables the content assist based on the state of the key
+ * {@link #CONTENT_ASSIST_ENABLED} in the passed memento.
+ *
+ * @param memento
+ * the memento where a key with {@link #CONTENT_ASSIST_ENABLED} with
+ * the enabled state of the content assist to be restored.
+ */
+ private void leaveMacroMode(IMemento memento, IMacroContext context) {
+ IEditorPart editorPart = EditorUtils.getTargetEditorPart(context);
+ if (editorPart != null) {
+ ITextOperationTarget textOperationTarget = editorPart.getAdapter(ITextOperationTarget.class);
+ if (textOperationTarget instanceof ITextOperationTargetExtension) {
+ ITextOperationTargetExtension targetExtension = (ITextOperationTargetExtension) textOperationTarget;
+ if (textOperationTarget instanceof ITextOperationTargetExtension) {
+ restore(memento, targetExtension, ISourceViewer.CONTENTASSIST_PROPOSALS, CONTENT_ASSIST_ENABLED);
+ restore(memento, targetExtension, ISourceViewer.QUICK_ASSIST, QUICK_ASSIST_ENABLED);
+ }
+ }
+
+ if (editorPart instanceof ITextEditor) {
+ ITextEditor textEditor = (ITextEditor) editorPart;
+ restore(memento, textEditor, ITextEditorActionConstants.CONTENT_ASSIST);
+ restore(memento, textEditor, ITextEditorActionConstants.QUICK_ASSIST);
+ restore(memento, textEditor, ITextEditorActionConstants.BLOCK_SELECTION_MODE);
+ }
+ }
+
+ }
+
+ /**
+ * Disables the content assist and saves the previous state on the passed
+ * memento (note that it's only saved if it is actually disabled here).
+ *
+ * @param memento
+ * memento where the previous state should be saved, to be properly
+ * restored later on in {@link #leaveMacroMode(IMemento)}.
+ */
+ private void enterMacroMode(IMemento memento, IMacroContext context) {
+ IEditorPart editorPart = EditorUtils.getTargetEditorPart(context);
+ if (editorPart instanceof ITextEditorExtension5) {
+ ITextEditorExtension5 iTextEditorExtension5 = (ITextEditorExtension5) editorPart;
+ if (iTextEditorExtension5.isBlockSelectionModeEnabled()) {
+ // Note: macro can't deal with block selections... there's nothing really
+ // inherent to not being able to work, but given:
+ // org.eclipse.jface.text.TextViewer.verifyEventInBlockSelection(VerifyEvent)
+ // and the fact that we don't generate events through the Display (because it's
+ // too error prone -- so much that it could target the wrong IDE instance for
+ // the events because it deals with system messages and not really events
+ // inside the IDE) and the fact that we can't force a new system message time
+ // for temporary events created internally, makes it really hard to work
+ // around the hack in verifyEventInBlockSelection.
+ // So, we simply disable block selection mode as well as the action which would
+ // activate it.
+
+ // Note: ideally we'd have a way to set a new time for the time returned in
+ // org.eclipse.swt.widgets.Display.getLastEventTime()
+ // -- as it is, internally the events time will be always the same because
+ // there's no API to reset it -- if possible we should reset it when we
+ // generate our internal events at:
+ // org.eclipse.ui.workbench.texteditor.macros.internal.StyledTextKeyDownMacroInstruction.execute(IMacroPlaybackContext)
+ iTextEditorExtension5.setBlockSelectionMode(false);
+ }
+ }
+
+ if (editorPart instanceof ITextEditor) {
+ ITextEditor textEditor = (ITextEditor) editorPart;
+ disable(memento, textEditor, ITextEditorActionConstants.CONTENT_ASSIST);
+ disable(memento, textEditor, ITextEditorActionConstants.QUICK_ASSIST);
+ disable(memento, textEditor, ITextEditorActionConstants.BLOCK_SELECTION_MODE);
+ }
+
+ if (editorPart != null) {
+ ITextOperationTarget textOperationTarget = editorPart.getAdapter(ITextOperationTarget.class);
+ if (textOperationTarget instanceof ITextOperationTargetExtension) {
+ ITextOperationTargetExtension targetExtension = (ITextOperationTargetExtension) textOperationTarget;
+
+ // Disable content assist and mark it to be restored later on
+ disable(memento, textOperationTarget, targetExtension, ISourceViewer.CONTENTASSIST_PROPOSALS,
+ CONTENT_ASSIST_ENABLED);
+ disable(memento, textOperationTarget, targetExtension, ISourceViewer.QUICK_ASSIST,
+ QUICK_ASSIST_ENABLED);
+ }
+ }
+ }
+
+ private void restore(IMemento memento, ITextOperationTargetExtension targetExtension, int operation,
+ String preference) {
+ Boolean contentAssistProposalsBeforMacroMode = memento.getBoolean(preference);
+ if (contentAssistProposalsBeforMacroMode != null) {
+ if ((contentAssistProposalsBeforMacroMode).booleanValue()) {
+ targetExtension.enableOperation(operation, true);
+ } else {
+ targetExtension.enableOperation(operation, false);
+ }
+ }
+ }
+
+ private void restore(IMemento memento, ITextEditor textEditor, String actionId) {
+ Boolean b = memento.getBoolean(actionId);
+ if (b != null && b) {
+ Control control = textEditor.getAdapter(Control.class);
+ if (control != null && !control.isDisposed()) {
+ // Do nothing if already disposed.
+ IAction action = textEditor.getAction(actionId);
+ if (action instanceof TextEditorAction) {
+ TextEditorAction textEditorAction = (TextEditorAction) action;
+ textEditorAction.setEditor(textEditor);
+ textEditorAction.update();
+ }
+ }
+ }
+ }
+
+ private void disable(IMemento memento, ITextOperationTarget textOperationTarget,
+ ITextOperationTargetExtension targetExtension, int operation, String preference) {
+ if (textOperationTarget.canDoOperation(operation)) {
+ memento.putBoolean(preference, true);
+ targetExtension.enableOperation(operation, false);
+ }
+ }
+
+ private void disable(IMemento memento, ITextEditor textEditor, String actionId) {
+ IAction action = textEditor.getAction(actionId);
+ if (action != null && action instanceof TextEditorAction) {
+ TextEditorAction textEditorAction = (TextEditorAction) action;
+ memento.putBoolean(actionId, true);
+ textEditorAction.setEditor(null);
+ textEditorAction.update();
+ }
+ }
+
+ @Override
+ public void onMacroPlaybackContextCreated(IMacroPlaybackContext context) {
+ EditorUtils.cacheTargetEditorPart(context);
+ EditorUtils.cacheTargetStyledText(context);
+ }
+
+ @Override
+ public void onMacroRecordContextCreated(IMacroRecordContext context) {
+ EditorUtils.cacheTargetEditorPart(context);
+ EditorUtils.cacheTargetStyledText(context);
+ }
+
+ /**
+ * Implemented to properly deal with macro recording/playback (i.e.: the editor
+ * may need to disable content assist during macro recording and it needs to
+ * record keystrokes to be played back afterwards).
+ */
+ @Override
+ public void macroStateChanged(EMacroService macroService, StateChange stateChange) {
+
+ if (stateChange == StateChange.RECORD_STARTED) {
+ enterMacroMode(macroService.getMacroRecordContext(), macroService.getMacroPlaybackContext());
+ enableRecording(macroService, macroService.getMacroRecordContext());
+
+ } else if (stateChange == StateChange.RECORD_FINISHED) {
+ leaveMacroMode(macroService.getMacroRecordContext(), macroService.getMacroPlaybackContext());
+ disableRecording(macroService.getMacroRecordContext());
+
+ } else if (stateChange == StateChange.PLAYBACK_STARTED) {
+ enterMacroMode(macroService.getMacroPlaybackContext(), macroService.getMacroRecordContext());
+
+ } else if (stateChange == StateChange.PLAYBACK_FINISHED) {
+ leaveMacroMode(macroService.getMacroPlaybackContext(), macroService.getMacroRecordContext());
+
+ }
+ }
+
+ private void enterMacroMode(IMacroContext context, IMacroContext otherContext) {
+ StyledText currentStyledText = EditorUtils.getTargetStyledText(context);
+ StyledText otherStyledText = EditorUtils.getTargetStyledText(otherContext);
+ if (currentStyledText == otherStyledText) {
+ return; // If they're the same in both it means we already entered macro mode in the
+ // other before.
+ }
+ Object object = context.get(MACRO_STYLED_TEXT_INSTALLER_MEMENTO);
+ if (object == null) {
+ XMLMemento mementoStateBeforeMacro = XMLMemento.createWriteRoot("AbstractTextEditorXmlMemento"); //$NON-NLS-1$
+ enterMacroMode(mementoStateBeforeMacro, context);
+ }
+ }
+
+ private void leaveMacroMode(IMacroContext context, IMacroContext otherContext) {
+ StyledText currentStyledText = EditorUtils.getTargetStyledText(context);
+ StyledText otherStyledText = EditorUtils.getTargetStyledText(otherContext);
+ if (currentStyledText == otherStyledText) {
+ return; // If they're the same in both it means we still can't exit macro mode.
+ }
+
+ // Restores content assist if it was disabled (based on the memento)
+ Object object = context.get(MACRO_STYLED_TEXT_INSTALLER_MEMENTO);
+ if (object instanceof XMLMemento) {
+ XMLMemento mementoStateBeforeMacro = (XMLMemento) object;
+ leaveMacroMode(mementoStateBeforeMacro, context);
+ }
+ }
+
+ private void enableRecording(EMacroService macroService, IMacroRecordContext context) {
+ // When recording install a recorder for key events (and uninstall
+ // if not recording).
+ // Note: affects only current editor
+ Object object = context.get(MACRO_STYLED_TEXT_INSTALLER_MACRO_RECORDER);
+ if (object == null) {
+ if (macroService.isRecording()) {
+ StyledText targetStyledText = EditorUtils.getTargetStyledText(context);
+ if (targetStyledText != null && !targetStyledText.isDisposed()) {
+ StyledTextMacroRecorder styledTextMacroRecorder = new StyledTextMacroRecorder(macroService);
+ styledTextMacroRecorder.install(targetStyledText);
+ context.set(MACRO_STYLED_TEXT_INSTALLER_MACRO_RECORDER, styledTextMacroRecorder);
+ }
+ }
+ }
+ }
+
+ private void disableRecording(IMacroRecordContext context) {
+ StyledText currentStyledText = EditorUtils.getTargetStyledText(context);
+ Object object = context.get(MACRO_STYLED_TEXT_INSTALLER_MACRO_RECORDER);
+ if (object instanceof StyledTextMacroRecorder) {
+ StyledTextMacroRecorder styledTextMacroRecorder = (StyledTextMacroRecorder) object;
+ if (currentStyledText != null && !currentStyledText.isDisposed()) {
+ styledTextMacroRecorder.uninstall(currentStyledText);
+ }
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/Messages.java b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/Messages.java
new file mode 100644
index 0000000..598abd1
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/Messages.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.ui.workbench.texteditor.macros.internal;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ *
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.ui.workbench.texteditor.macros.internal.messages"; //$NON-NLS-1$
+ public static String NotifyMacroOnlyInCurrentEditor_NotRecording;
+ public static String NotifyMacroOnlyInCurrentEditor_Recording;
+ public static String StyledTextKeyDownMacroInstruction_KeyDown;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/NotifyMacroOnlyInCurrentEditor.java b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/NotifyMacroOnlyInCurrentEditor.java
new file mode 100644
index 0000000..0feba10
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/NotifyMacroOnlyInCurrentEditor.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.ui.workbench.texteditor.macros.internal;
+
+import org.eclipse.e4.core.macros.CancelMacroPlaybackException;
+import org.eclipse.e4.core.macros.CancelMacroRecordingException;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.IMacroRecordContext;
+import org.eclipse.e4.ui.macros.internal.EditorUtils;
+import org.eclipse.e4.ui.macros.internal.UserNotifications;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IWindowListener;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Used to notify that macro is only available in the initial editor.
+ */
+public class NotifyMacroOnlyInCurrentEditor {
+
+ /**
+ * When a new window is opened/activated, add the needed listeners.
+ */
+ private class WindowsListener implements IWindowListener {
+ @Override
+ public void windowOpened(IWorkbenchWindow window) {
+ addListeners(window);
+ }
+
+ @Override
+ public void windowClosed(IWorkbenchWindow window) {
+ }
+
+ @Override
+ public void windowActivated(IWorkbenchWindow window) {
+ addListeners(window);
+ }
+
+ @Override
+ public void windowDeactivated(IWorkbenchWindow window) {
+ }
+ }
+
+ /**
+ * When a new part is made visible or is opened, check if it's the one active
+ * when macro was activated.
+ */
+ private class MacroPartListener implements IPartListener2 {
+
+ @Override
+ public void partVisible(IWorkbenchPartReference partRef) {
+ checkCurrentEditor();
+ }
+
+ @Override
+ public void partOpened(IWorkbenchPartReference partRef) {
+ checkCurrentEditor();
+ }
+
+ @Override
+ public void partInputChanged(IWorkbenchPartReference partRef) {
+
+ }
+
+ @Override
+ public void partHidden(IWorkbenchPartReference partRef) {
+
+ }
+
+ @Override
+ public void partDeactivated(IWorkbenchPartReference partRef) {
+
+ }
+
+ @Override
+ public void partClosed(IWorkbenchPartReference partRef) {
+
+ }
+
+ @Override
+ public void partBroughtToTop(IWorkbenchPartReference partRef) {
+
+ }
+
+ @Override
+ public void partActivated(IWorkbenchPartReference partRef) {
+ checkCurrentEditor();
+ }
+ }
+
+ private MacroPartListener fPartListener = new MacroPartListener();
+
+ private WindowsListener fWindowsListener = new WindowsListener();
+
+ /**
+ * The macro service to be listened to.
+ */
+ private EMacroService fMacroService;
+
+ /**
+ * The last editor checked.
+ */
+ private StyledText fLastEditor;
+
+ /**
+ * @param macroService
+ * the macro service.
+ */
+ public NotifyMacroOnlyInCurrentEditor(EMacroService macroService) {
+ this.fMacroService = macroService;
+ }
+
+ /**
+ * Checks that the current editor didn't change (if it did, notify the user that
+ * recording doesn't work in other editors).
+ */
+ private void checkCurrentEditor() {
+ IMacroRecordContext macroRecordContext = this.fMacroService.getMacroRecordContext();
+ if (macroRecordContext != null) {
+ StyledText currentStyledText = EditorUtils.getActiveStyledText();
+ StyledText targetStyledText = EditorUtils.getTargetStyledText(macroRecordContext);
+ if (targetStyledText != currentStyledText && currentStyledText != fLastEditor) {
+ UserNotifications.setMessage(Messages.NotifyMacroOnlyInCurrentEditor_NotRecording);
+ UserNotifications.notifyCurrentEditor();
+ } else if (targetStyledText == currentStyledText && fLastEditor != null
+ && fLastEditor != currentStyledText) {
+ UserNotifications.setMessage(Messages.NotifyMacroOnlyInCurrentEditor_Recording);
+ }
+ fLastEditor = currentStyledText;
+ }
+ }
+
+ /**
+ * Check if there's some active editor when the macro recording starts.
+ *
+ * @throws CancelMacroRecordingException
+ */
+ public void checkEditorActiveForMacroRecording() throws CancelMacroRecordingException {
+ StyledText currentStyledText = EditorUtils.getActiveStyledText();
+ if (currentStyledText == null) {
+ UserNotifications.setMessage(Messages.NotifyMacroOnlyInCurrentEditor_NotRecording);
+ UserNotifications.notifyNoEditorOnMacroRecordStartup();
+ throw new CancelMacroRecordingException();
+ }
+ }
+
+ /**
+ * Check if there's some active editor when the macro playback starts.
+ *
+ * @throws CancelMacroPlaybackException
+ */
+ public void checkEditorActiveForMacroPlayback() throws CancelMacroPlaybackException {
+ StyledText currentStyledText = EditorUtils.getActiveStyledText();
+ if (currentStyledText == null) {
+ UserNotifications.notifyNoEditorOnMacroPlaybackStartup();
+ throw new CancelMacroPlaybackException();
+ }
+ }
+
+
+ private void addListeners(IWorkbenchWindow window) {
+ window.getPartService().addPartListener(fPartListener);
+ }
+
+ private void removeListeners(IWorkbenchWindow window) {
+ window.getPartService().removePartListener(fPartListener);
+ }
+
+ /**
+ * Install listeners regarding macro only for current editor.
+ */
+ public void install() {
+ PlatformUI.getWorkbench().addWindowListener(fWindowsListener);
+ for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
+ addListeners(window);
+ }
+ }
+
+ /**
+ * Uninstall listeners regarding macro only for current editor.
+ */
+ public void uninstall() {
+ fLastEditor = null;
+ for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
+ removeListeners(window);
+ }
+ PlatformUI.getWorkbench().removeWindowListener(fWindowsListener);
+ }
+
+
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/StyledTextKeyDownMacroInstruction.java b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/StyledTextKeyDownMacroInstruction.java
new file mode 100644
index 0000000..d95d7b9
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/StyledTextKeyDownMacroInstruction.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.ui.workbench.texteditor.macros.internal;
+
+import java.util.Map;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.internal.JSONHelper;
+import org.eclipse.e4.ui.macros.internal.EditorUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * A macro instruction to replay a key down (always followed by a key up).
+ */
+/* default */ class StyledTextKeyDownMacroInstruction extends AbstractSWTEventMacroInstruction {
+
+ private static final String ID = "KeyEvent"; //$NON-NLS-1$
+
+ public StyledTextKeyDownMacroInstruction(Event event) {
+ super(event);
+ }
+
+ @Override
+ public void execute(IMacroPlaybackContext macroPlaybackContext) {
+ StyledText styledText = EditorUtils.getTargetStyledText(macroPlaybackContext);
+ if (styledText != null) {
+ if (styledText.isDisposed()) {
+ return;
+ }
+ Event keyDownEvent = copyEvent(fEvent);
+ styledText.notifyListeners(SWT.KeyDown, keyDownEvent);
+
+ if (styledText.isDisposed()) {
+ return;
+ }
+
+ // Key up is also needed to update the clipboard.
+ Event keyUpEvent = copyEvent(fEvent);
+ keyUpEvent.type = SWT.KeyUp;
+ styledText.notifyListeners(SWT.KeyUp, keyUpEvent);
+ }
+ }
+
+ @Override
+ protected int getEventType() {
+ return SWT.KeyDown;
+ }
+
+ @Override
+ public String getId() {
+ return ID;
+ }
+
+ /* default */ static StyledTextKeyDownMacroInstruction fromMap(Map<String, String> map) {
+ Event event = createEventFromMap(map, SWT.KeyDown);
+ return new StyledTextKeyDownMacroInstruction(event);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return Messages.StyledTextKeyDownMacroInstruction_KeyDown
+ + JSONHelper.quote(Character.toString(this.fEvent.character));
+ }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/StyledTextKeyDownMacroInstructionFactory.java b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/StyledTextKeyDownMacroInstructionFactory.java
new file mode 100644
index 0000000..64d8f8c
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/StyledTextKeyDownMacroInstructionFactory.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.ui.workbench.texteditor.macros.internal;
+
+import java.util.Map;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroInstructionFactory;
+
+/**
+ */
+public class StyledTextKeyDownMacroInstructionFactory implements IMacroInstructionFactory {
+
+ @Override
+ public IMacroInstruction create(Map<String, String> stringMap) {
+ return StyledTextKeyDownMacroInstruction.fromMap(stringMap);
+ }
+
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/StyledTextMacroRecorder.java b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/StyledTextMacroRecorder.java
new file mode 100644
index 0000000..8f3684b
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/StyledTextMacroRecorder.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.ui.workbench.texteditor.macros.internal;
+
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/**
+ * A listener that will record actions done in a StyledText and add them to the
+ * macro.
+ */
+public class StyledTextMacroRecorder implements Listener {
+
+ private final EMacroService fMacroService;
+
+ public StyledTextMacroRecorder(EMacroService macroService) {
+ this.fMacroService = macroService;
+ }
+
+ @Override
+ public void handleEvent(Event event) {
+ if (event.type == SWT.KeyDown && fMacroService.isRecording()) {
+ // Note: we only currently record key down actions and replay each
+ // one with KeyDown and KeyUp. In practice, having a key pressed
+ // down multiple times down and only once up gives the same result
+ // as doing a down/up at each step.
+ fMacroService.addMacroInstruction(new StyledTextKeyDownMacroInstruction(event), event,
+ EMacroService.PRIORITY_LOW);
+ }
+ }
+
+ public void uninstall(StyledText textWidget) {
+ textWidget.removeListener(SWT.KeyDown, this);
+ }
+
+ public void install(StyledText textWidget) {
+ textWidget.addListener(SWT.KeyDown, this);
+ }
+}
diff --git a/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/messages.properties b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/messages.properties
new file mode 100644
index 0000000..844b35d
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench.texteditor.macros/src/org/eclipse/ui/workbench/texteditor/macros/internal/messages.properties
@@ -0,0 +1,3 @@
+NotifyMacroOnlyInCurrentEditor_NotRecording=Not recording
+NotifyMacroOnlyInCurrentEditor_Recording=Recording
+StyledTextKeyDownMacroInstruction_KeyDown=KeyDown:
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 4e90238..a8c01ef 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -26,10 +26,11 @@
<module>org.eclipse.e4.ui.keys.common</module>
<module>org.eclipse.e4.ui.naturist</module>
<module>org.eclipse.e4.jdt.scope</module>
- <module>org.eclipse.e4.ui.macros.jdt</module>
- <module>org.eclipse.e4.ui.macros</module>
<module>org.eclipse.ui.glance</module>
<module>org.eclipse.ui.regex</module>
+ <module>org.eclipse.e4.core.macros</module>
+ <module>org.eclipse.e4.ui.macros</module>
+ <module>org.eclipse.ui.workbench.texteditor.macros</module>
</modules>
</project>
diff --git a/features/org.eclipse.e4.ui.macros.feature/.project b/features/org.eclipse.e4.ui.macros.feature/.project
new file mode 100644
index 0000000..b2d50ef
--- /dev/null
+++ b/features/org.eclipse.e4.ui.macros.feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.e4.ui.macros.feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
diff --git a/features/org.eclipse.e4.ui.macros.feature/build.properties b/features/org.eclipse.e4.ui.macros.feature/build.properties
new file mode 100644
index 0000000..64f93a9
--- /dev/null
+++ b/features/org.eclipse.e4.ui.macros.feature/build.properties
@@ -0,0 +1 @@
+bin.includes = feature.xml
diff --git a/features/org.eclipse.e4.ui.macros.feature/feature.xml b/features/org.eclipse.e4.ui.macros.feature/feature.xml
new file mode 100644
index 0000000..774fabc
--- /dev/null
+++ b/features/org.eclipse.e4.ui.macros.feature/feature.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.eclipse.e4.ui.macros.feature"
+ label="Eclipse Macros"
+ version="0.1.0.qualifier"
+ provider-name="Eclipse.org">
+
+ <description>
+ Macro support for Eclipse
+ </description>
+
+ <copyright>
+ Copyright (c) 2017 Fabio Zadrozny and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License
+v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v10.html
+ </copyright>
+
+ <license url="http://www.eclipse.org/legal/epl-v10.html">
+ Eclipse Public License
+ </license>
+
+ <plugin
+ id="org.eclipse.e4.core.macros"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.e4.ui.macros"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.ui.workbench.texteditor.macros"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
diff --git a/features/org.eclipse.e4.ui.macros.feature/pom.xml b/features/org.eclipse.e4.ui.macros.feature/pom.xml
new file mode 100644
index 0000000..f06cb5b
--- /dev/null
+++ b/features/org.eclipse.e4.ui.macros.feature/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.e4.ui</groupId>
+ <artifactId>e4-ui-aggregator</artifactId>
+ <version>0.17.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+
+ <groupId>org.eclipse.e4</groupId>
+ <artifactId>org.eclipse.e4.ui.macros.feature</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <packaging>eclipse-feature</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.tycho.extras</groupId>
+ <artifactId>tycho-source-feature-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <id>source-feature</id>
+ <goals>
+ <goal>source-feature</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>tycho-p2-plugin</artifactId>
+ <version>${tycho.version}</version>
+ <executions>
+ <execution>
+ <id>attached-p2-metadata</id>
+ <phase>package</phase>
+ <goals>
+ <goal>p2-metadata</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/features/pom.xml b/features/pom.xml
index 0ca970f..a48a29f 100644
--- a/features/pom.xml
+++ b/features/pom.xml
@@ -26,6 +26,7 @@
<module>org.eclipse.e4.ui.keys.feature</module>
<module>org.eclipse.e4.ui.naturist.feature</module>
<module>org.eclipse.ui.glance.feature</module>
+ <module>org.eclipse.e4.ui.macros.feature</module>
</modules>
</project>
diff --git a/pom.xml b/pom.xml
index 0c52e94..8e8907e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,6 +39,7 @@
<modules>
<module>tests/org.eclipse.e4.naturist.tests</module>
<module>tests/org.eclipse.e4.jdt.scope.tests</module>
+ <module>tests/org.eclipse.e4.ui.macros.tests</module>
<module>build/org.eclipse.e4.ui.update</module>
<module>bundles</module>
<module>features</module>
diff --git a/tests/org.eclipse.e4.ui.macros.tests/.classpath b/tests/org.eclipse.e4.ui.macros.tests/.classpath
new file mode 100644
index 0000000..4f83b23
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/.project b/tests/org.eclipse.e4.ui.macros.tests/.project
similarity index 92%
rename from bundles/org.eclipse.e4.ui.macros.jdt/.project
rename to tests/org.eclipse.e4.ui.macros.tests/.project
index 4babb46..f65caa5 100644
--- a/bundles/org.eclipse.e4.ui.macros.jdt/.project
+++ b/tests/org.eclipse.e4.ui.macros.tests/.project
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>org.eclipse.e4.ui.macros.jdt</name>
+ <name>org.eclipse.e4.ui.macros.tests</name>
<comment></comment>
<projects>
</projects>
diff --git a/tests/org.eclipse.e4.ui.macros.tests/.settings/org.eclipse.core.runtime.prefs b/tests/org.eclipse.e4.ui.macros.tests/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/tests/org.eclipse.e4.ui.macros.tests/.settings/org.eclipse.jdt.core.prefs b/tests/org.eclipse.e4.ui.macros.tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..6d43b76
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,292 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=120
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/tests/org.eclipse.e4.ui.macros.tests/.settings/org.eclipse.jdt.ui.prefs b/tests/org.eclipse.e4.ui.macros.tests/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..d7de1c3
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,62 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=org.eclipse.jdt.ui.default.eclipse_profile
+formatter_settings_version=12
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=false
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=true
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=false
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/tests/org.eclipse.e4.ui.macros.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.e4.ui.macros.tests/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..7297136
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Macro tests
+Bundle-SymbolicName: org.eclipse.e4.ui.macros.tests;singleton:=true
+Bundle-Activator: org.eclipse.e4.ui.macros.tests.Activator
+Bundle-Version: 0.1.0.qualifier
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.junit,
+ org.eclipse.e4.core.macros,
+ org.eclipse.e4.core.contexts,
+ org.eclipse.e4.core.di,
+ org.eclipse.e4.ui.bindings,
+ org.eclipse.e4.core.commands,
+ org.eclipse.e4.ui.services,
+ org.eclipse.e4.ui.macros
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.e4.ui.macros.jdt/build.properties b/tests/org.eclipse.e4.ui.macros.tests/build.properties
similarity index 73%
rename from bundles/org.eclipse.e4.ui.macros.jdt/build.properties
rename to tests/org.eclipse.e4.ui.macros.tests/build.properties
index e3023e1..e9863e2 100644
--- a/bundles/org.eclipse.e4.ui.macros.jdt/build.properties
+++ b/tests/org.eclipse.e4.ui.macros.tests/build.properties
@@ -2,4 +2,4 @@
output.. = bin/
bin.includes = META-INF/,\
.,\
- fragment.xml
+ plugin.xml
diff --git a/tests/org.eclipse.e4.ui.macros.tests/forceQualifierUpdate.txt b/tests/org.eclipse.e4.ui.macros.tests/forceQualifierUpdate.txt
new file mode 100644
index 0000000..8ad7a91
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/forceQualifierUpdate.txt
@@ -0,0 +1 @@
+# To force a version qualifier update add the bug here
\ No newline at end of file
diff --git a/tests/org.eclipse.e4.ui.macros.tests/pom.xml b/tests/org.eclipse.e4.ui.macros.tests/pom.xml
new file mode 100644
index 0000000..47664de
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/pom.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Copyright (c) 2017 Fabio Zadrozny, and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.e4.ui</groupId>
+ <artifactId>e4-ui-aggregator</artifactId>
+ <version>0.17.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+
+ <groupId>org.eclipse.e4</groupId>
+ <artifactId>org.eclipse.e4.ui.macros.tests</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <packaging>eclipse-test-plugin</packaging>
+
+</project>
diff --git a/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/Activator.java b/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/Activator.java
new file mode 100644
index 0000000..e9315b4
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/Activator.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.tests;
+
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.e4.ui.macros.tests"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ private IEclipseContext appContext;
+
+ private IEclipseContext serviceContext;
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ plugin = this;
+ serviceContext = EclipseContextFactory.getServiceContext(context);
+ appContext = serviceContext.createChild();
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ serviceContext.dispose();
+ plugin = null;
+ }
+
+ public IEclipseContext getGlobalContext() {
+ return appContext;
+ }
+
+}
diff --git a/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/JSONHelperTest.java b/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/JSONHelperTest.java
new file mode 100644
index 0000000..c3da94d
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/JSONHelperTest.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.tests;
+
+import org.eclipse.e4.core.macros.internal.JSONHelper;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JSONHelperTest {
+
+ @Test
+ public void testJSONHelper() {
+ StringBuilder builder = new StringBuilder("chars\"\\/\b\f\n\r\t");
+ builder.append(new Character((char) 5));
+ builder.append(new Character((char) 6));
+ String quoted = JSONHelper.quote(builder.toString());
+ Assert.assertEquals("\"chars\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0005\\u0006\"", quoted);
+ }
+}
diff --git a/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/KeyBindingDispatcherMacroIntegrationTest.java b/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/KeyBindingDispatcherMacroIntegrationTest.java
new file mode 100644
index 0000000..da61aa1
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/KeyBindingDispatcherMacroIntegrationTest.java
@@ -0,0 +1,307 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.e4.core.commands.CommandServiceAddon;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.IMacroRecordContext;
+import org.eclipse.e4.core.macros.IMacroStateListener;
+import org.eclipse.e4.core.macros.internal.MacroServiceImplementation;
+import org.eclipse.e4.ui.bindings.BindingServiceAddon;
+import org.eclipse.e4.ui.bindings.EBindingService;
+import org.eclipse.e4.ui.bindings.internal.BindingTable;
+import org.eclipse.e4.ui.bindings.internal.BindingTableManager;
+import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher;
+import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.KeyDownFilter;
+import org.eclipse.e4.ui.macros.internal.keybindings.CommandManagerExecutionListener;
+import org.eclipse.e4.ui.macros.internal.keybindings.CommandManagerExecutionListenerInstaller;
+import org.eclipse.e4.ui.services.ContextServiceAddon;
+import org.eclipse.e4.ui.services.EContextService;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+@SuppressWarnings("restriction")
+public class KeyBindingDispatcherMacroIntegrationTest {
+
+ private static final String ID_DIALOG = "org.eclipse.ui.contexts.dialog";
+ private static final String ID_DIALOG_AND_WINDOW = "org.eclipse.ui.contexts.dialogAndWindow";
+ private static final String ID_WINDOW = "org.eclipse.ui.contexts.window";
+
+ final static String[] CONTEXTS = { ID_DIALOG_AND_WINDOW, "DAW", null, ID_DIALOG, "Dialog", ID_DIALOG_AND_WINDOW,
+ ID_WINDOW, "Window", ID_DIALOG_AND_WINDOW, };
+
+ private static final String TEST_CAT1 = "test.cat1";
+ private static final String TEST_ID1 = "test.id1";
+
+ static class CallHandler {
+ public boolean q1;
+ public boolean q2;
+
+ @CanExecute
+ public boolean canExecute() {
+ q1 = true;
+ return true;
+ }
+
+ @Execute
+ public Object execute() {
+ q2 = true;
+ if (q1) {
+ return Boolean.TRUE;
+ }
+ return Boolean.FALSE;
+ }
+ }
+
+ private Display display;
+ private IEclipseContext workbenchContext;
+ private CallHandler handler;
+ private File fMacrosDirectory;
+ private Shell shell;
+ private StyledText styledText;
+ private KeyDownFilter dispatcherListener;
+
+ private void defineCommands(IEclipseContext context) {
+ ECommandService cs = workbenchContext.get(ECommandService.class);
+ Category category = cs.defineCategory(TEST_CAT1, "CAT1", null);
+ cs.defineCommand(TEST_ID1, "ID1", null, category, null);
+ ParameterizedCommand cmd = cs.createCommand(TEST_ID1, null);
+ EHandlerService hs = workbenchContext.get(EHandlerService.class);
+ handler = new CallHandler();
+ hs.activateHandler(TEST_ID1, handler);
+ EBindingService bs = workbenchContext.get(EBindingService.class);
+ // As we're using the default display, we have to generate a unique sequence
+ // otherwise the default installed key filter may eat it.
+ TriggerSequence seq = bs.createSequence("CTRL+I");
+ Binding db = createDefaultBinding(bs, seq, cmd);
+ bs.activateBinding(db);
+ }
+
+ private Binding createDefaultBinding(EBindingService bs, TriggerSequence sequence, ParameterizedCommand command) {
+
+ Map<String, String> attrs = new HashMap<>();
+ attrs.put("schemeId", "org.eclipse.ui.defaultAcceleratorConfiguration");
+
+ return bs.createBinding(sequence, command, ID_WINDOW, attrs);
+ }
+
+ private void defineContexts(IEclipseContext context) {
+ ContextManager contextManager = context.get(ContextManager.class);
+ for (int i = 0; i < CONTEXTS.length; i += 3) {
+ Context c = contextManager.getContext(CONTEXTS[i]);
+ c.define(CONTEXTS[i + 1], null, CONTEXTS[i + 2]);
+ }
+
+ EContextService cs = context.get(EContextService.class);
+ cs.activateContext(ID_DIALOG_AND_WINDOW);
+ cs.activateContext(ID_WINDOW);
+ }
+
+ private void defineBindingTables(IEclipseContext context) {
+ BindingTableManager btm = context.get(BindingTableManager.class);
+ ContextManager cm = context.get(ContextManager.class);
+ btm.addTable(new BindingTable(cm.getContext(ID_DIALOG_AND_WINDOW)));
+ btm.addTable(new BindingTable(cm.getContext(ID_WINDOW)));
+ btm.addTable(new BindingTable(cm.getContext(ID_DIALOG)));
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ display = Display.getDefault();
+ shell = new Shell(display, SWT.NONE);
+ styledText = new StyledText(shell, SWT.NONE);
+
+ IEclipseContext globalContext = Activator.getDefault().getGlobalContext();
+ workbenchContext = globalContext.createChild("workbenchContext");
+ ContextInjectionFactory.make(CommandServiceAddon.class, workbenchContext);
+ ContextInjectionFactory.make(ContextServiceAddon.class, workbenchContext);
+ ContextInjectionFactory.make(BindingServiceAddon.class, workbenchContext);
+ defineContexts(workbenchContext);
+ defineBindingTables(workbenchContext);
+ defineCommands(workbenchContext);
+
+ KeyBindingDispatcher dispatcher = new KeyBindingDispatcher();
+ workbenchContext.set(KeyBindingDispatcher.class, dispatcher);
+ ContextInjectionFactory.inject(dispatcher, workbenchContext);
+
+ workbenchContext.set(EMacroService.class.getName(),
+ ContextInjectionFactory.make(MacroServiceImplementation.class, workbenchContext));
+
+ dispatcherListener = dispatcher.getKeyDownFilter();
+ display.addFilter(SWT.KeyDown, dispatcherListener);
+ display.addFilter(SWT.Traverse, dispatcherListener);
+
+ assertFalse(handler.q2);
+
+ fMacrosDirectory = folder.getRoot();
+ EMacroService macroService = workbenchContext.get(EMacroService.class);
+ ((MacroServiceImplementation) macroService).getMacroManager().setMacrosDirectories(fMacrosDirectory);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ workbenchContext.dispose();
+ workbenchContext = null;
+ styledText.dispose();
+ styledText = null;
+ shell.dispose();
+ shell = null;
+ }
+
+ private void notifyCtrlI(Control control) {
+ Event event = new Event();
+ event.type = SWT.KeyDown;
+ event.keyCode = SWT.CTRL;
+ control.notifyListeners(SWT.KeyDown, event);
+
+ event = new Event();
+ event.type = SWT.KeyDown;
+ event.stateMask = SWT.CTRL;
+ event.keyCode = 'I';
+ control.notifyListeners(SWT.KeyDown, event);
+ }
+
+ private void startRecording(EMacroService macroService) throws Exception {
+ macroService.toggleMacroRecord();
+ assertTrue(macroService.isRecording());
+ IMacroRecordContext macroRecordContext = macroService.getMacroRecordContext();
+ macroRecordContext.set("target_styled_text", styledText); // org.eclipse.e4.ui.macros.Activator.TARGET_STYLED_TEXT
+
+ Assert.assertEquals(
+ Arrays.asList("org.eclipse.e4.ui.macros.internal.actions.KeepMacroUIUpdated",
+ "org.eclipse.e4.ui.macros.internal.keybindings.CommandManagerExecutionListenerInstaller"),
+ getRegisteredClasses(macroService));
+ IMacroStateListener[] macroStateListeners = ((MacroServiceImplementation) macroService)
+ .getMacroStateListeners();
+ boolean found = false;
+ for (IMacroStateListener iMacroStateListener : macroStateListeners) {
+ if (iMacroStateListener instanceof CommandManagerExecutionListenerInstaller) {
+ CommandManagerExecutionListenerInstaller commandManagerExecutionListenerInstaller = (CommandManagerExecutionListenerInstaller) iMacroStateListener;
+ // Make sure that we accept any event while testing.
+ CommandManagerExecutionListener commandManagerExecutionListener = commandManagerExecutionListenerInstaller
+ .getCommandManagerExecutionListener();
+ Field field = CommandManagerExecutionListener.class.getDeclaredField("fFilter");
+ field.setAccessible(true);
+ field.set(commandManagerExecutionListener, new CommandManagerExecutionListener.IFilter() {
+
+ @Override
+ public boolean acceptEvent(Event swtEvent) {
+ return true;
+ }
+ });
+ found = true;
+ }
+ }
+ Assert.assertTrue(found);
+ }
+
+ private void finishRecording(EMacroService macroService) {
+ macroService.toggleMacroRecord();
+ assertFalse(macroService.isRecording());
+ }
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ @Test
+ public void testMacroIntegration() throws Exception {
+ EMacroService macroService = workbenchContext.get(EMacroService.class);
+ // Before the first record, it should be empty (loaded on demand).
+ Assert.assertEquals(new ArrayList<>(), getRegisteredClasses(macroService));
+ startRecording(macroService);
+
+ notifyCtrlI(styledText);
+ assertTrue(handler.q2);
+ assertEquals(macroService.getLenOfMacroBeingRecorded(), 1);
+
+ finishRecording(macroService);
+
+ handler.q2 = false;
+ macroService.playbackLastMacro();
+ assertTrue(handler.q2);
+ }
+
+ public List<String> getRegisteredClasses(EMacroService macroService) {
+ IMacroStateListener[] macroStateListeners = ((MacroServiceImplementation) macroService)
+ .getMacroStateListeners();
+ List<String> classes = Arrays.stream(macroStateListeners).map(m -> m.getClass().getName()).sorted()
+ .collect(Collectors.toList());
+ return classes;
+ }
+
+ @Test
+ public void testMacroIntegrationSaveRestore() throws Exception {
+ FilenameFilter macrosFilter = new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".js");
+ }
+ };
+ assertEquals(0, fMacrosDirectory.list(macrosFilter).length);
+
+ EMacroService macroService = workbenchContext.get(EMacroService.class);
+
+ assertFalse(handler.q2);
+
+ startRecording(macroService);
+ notifyCtrlI(styledText);
+ assertTrue(handler.q2);
+ assertEquals(macroService.getLenOfMacroBeingRecorded(), 1);
+ finishRecording(macroService);
+
+ // Macro was saved in the dir.
+ assertEquals(1, fMacrosDirectory.list(macrosFilter).length);
+
+ // Check if reloading from disk and playing it back works.
+ ((MacroServiceImplementation) macroService).getMacroManager().reloadMacros();
+ handler.q2 = false;
+ macroService.playbackLastMacro();
+ assertTrue(handler.q2);
+ }
+
+}
diff --git a/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/MacroTest.java b/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/MacroTest.java
new file mode 100644
index 0000000..1b8a9f0
--- /dev/null
+++ b/tests/org.eclipse.e4.ui.macros.tests/src/org/eclipse/e4/ui/macros/tests/MacroTest.java
@@ -0,0 +1,343 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Fabio Zadrozny and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabio Zadrozny - initial API and implementation - http://eclip.se/8519
+ *******************************************************************************/
+package org.eclipse.e4.ui.macros.tests;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.e4.core.macros.CancelMacroRecordingException;
+import org.eclipse.e4.core.macros.EMacroService;
+import org.eclipse.e4.core.macros.IMacroInstruction;
+import org.eclipse.e4.core.macros.IMacroInstructionFactory;
+import org.eclipse.e4.core.macros.IMacroPlaybackContext;
+import org.eclipse.e4.core.macros.IMacroStateListener;
+import org.eclipse.e4.core.macros.internal.MacroManager;
+import org.eclipse.e4.core.macros.internal.MacroManager.PathAndTime;
+import org.eclipse.e4.core.macros.internal.MacroServiceImplementation;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class MacroTest {
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ private static class PlaybackContext implements IMacroPlaybackContext {
+
+ public StringBuffer buffer = new StringBuffer();
+
+ private Map<String, IMacroInstructionFactory> fMacroInstructionIdToFactory;
+
+ public PlaybackContext(Map<String, IMacroInstructionFactory> macroInstructionIdToFactory) {
+ this.fMacroInstructionIdToFactory = macroInstructionIdToFactory;
+ }
+
+ public void recordPlayback(String name) {
+ if (buffer.length() > 0) {
+ buffer.append("\n");
+ }
+ buffer.append(name);
+ }
+
+ @Override
+ public IMacroInstruction createMacroInstruction(String macroInstructionId, Map<String, String> stringMap)
+ throws Exception {
+ return fMacroInstructionIdToFactory.get(macroInstructionId).create(stringMap);
+ }
+
+ private final Map<Object, Object> ctx = new HashMap<>();
+
+ @Override
+ public Object get(String key) {
+ return ctx.get(key);
+ }
+
+ @Override
+ public void set(String key, Object value) {
+ ctx.put(key, value);
+ }
+ }
+
+ private static class DummyMacroInstruction implements IMacroInstruction {
+
+ private String fName;
+
+ public DummyMacroInstruction(String name) {
+ this.fName = name;
+ }
+
+ @Override
+ public void execute(IMacroPlaybackContext macroPlaybackContext) {
+ ((PlaybackContext) macroPlaybackContext).recordPlayback(this.fName);
+ }
+
+ @Override
+ public String getId() {
+ return "dummy";
+ }
+
+ @Override
+ public String toString() {
+ return "Dummy macro instruction";
+ }
+
+ @Override
+ public Map<String, String> toMap() {
+ HashMap<String, String> map = new HashMap<>();
+ map.put("dummyKey", "dummyValue");
+ map.put("name", this.fName);
+ return map;
+ }
+
+ }
+
+ @Test
+ public void testRecordingState() throws Exception {
+ Map<String, IMacroInstructionFactory> macroInstructionIdToFactory = makeMacroInstructionIdToFactory();
+ MacroServiceImplementation macroService = new MacroServiceImplementation(null, null);
+ Field field = macroService.getClass().getDeclaredField("fMacroInstructionIdToFactory");
+ field.setAccessible(true);
+ field.set(macroService, macroInstructionIdToFactory);
+ File root = folder.getRoot();
+ macroService.getMacroManager().setMacrosDirectories(root);
+ final StringBuilder buf = new StringBuilder();
+ macroService.getMacroManager().addMacroStateListener(new IMacroStateListener() {
+
+ @Override
+ public void macroStateChanged(EMacroService macroService, StateChange stateChange) {
+ buf.append("rec: ").append(macroService.isRecording()).append(" play: ")
+ .append(macroService.isPlayingBack()).append("\n");
+ }
+ });
+
+ Assert.assertFalse(macroService.isRecording());
+ Assert.assertEquals("", buf.toString());
+
+ macroService.toggleMacroRecord();
+ Assert.assertEquals("rec: true play: false\n", buf.toString());
+ buf.setLength(0);
+ Assert.assertTrue(macroService.isRecording());
+
+ // Add something, otherwise no macro will be recorded
+ macroService.addMacroInstruction(new DummyMacroInstruction("test"));
+
+ macroService.toggleMacroRecord();
+ Assert.assertEquals("rec: false play: false\n", buf.toString());
+ buf.setLength(0);
+ Assert.assertFalse(macroService.isRecording());
+
+ PlaybackContext playbackContext = new PlaybackContext(macroInstructionIdToFactory);
+ macroService.getMacroManager().playbackLastMacro(macroService, playbackContext);
+ Assert.assertEquals("rec: false play: true\n"
+ + "rec: false play: false\n", buf.toString());
+ buf.setLength(0);
+
+ macroService.toggleMacroRecord();
+ macroService.getMacroManager().playbackLastMacro(macroService, playbackContext);
+ macroService.toggleMacroRecord();
+ Assert.assertEquals(
+ "rec: true play: false\n"
+ + "rec: true play: true\n"
+ + "rec: true play: false\n"
+ + "rec: false play: false\n",
+ buf.toString());
+ }
+
+ @Test
+ public void testAddMacroInstructions() throws Exception {
+ MacroManager macroManager = new MacroManager();
+ Map<String, IMacroInstructionFactory> macroInstructionIdToFactory = makeMacroInstructionIdToFactory();
+ PlaybackContext playbackContext = new PlaybackContext(macroInstructionIdToFactory);
+ macroManager.toggleMacroRecord(null, macroInstructionIdToFactory);
+ Assert.assertTrue(macroManager.isRecording());
+ macroManager.addMacroInstruction(new DummyMacroInstruction("macro1"));
+ macroManager.addMacroInstruction(new DummyMacroInstruction("macro2"));
+ macroManager.toggleMacroRecord(null, macroInstructionIdToFactory);
+ Assert.assertFalse(macroManager.isRecording());
+
+ macroManager.playbackLastMacro(null, playbackContext);
+ Assert.assertEquals("macro1\nmacro2", playbackContext.buffer.toString());
+ }
+
+ @Test
+ public void testAddMacroInstructionPriority() throws Exception {
+ MacroManager macroManager = new MacroManager();
+ Map<String, IMacroInstructionFactory> macroInstructionIdToFactory = makeMacroInstructionIdToFactory();
+ PlaybackContext playbackContext = new PlaybackContext(macroInstructionIdToFactory);
+ macroManager.toggleMacroRecord(null, macroInstructionIdToFactory);
+ Assert.assertTrue(macroManager.isRecording());
+ Object ev = new Integer(1);
+ macroManager.addMacroInstruction(new DummyMacroInstruction("macro1"), ev, 2);
+ Assert.assertEquals(1, macroManager.getLenOfMacroBeingRecorded());
+ macroManager.addMacroInstruction(new DummyMacroInstruction("macro2"), ev, 1); // will not replace it
+ Assert.assertEquals(1, macroManager.getLenOfMacroBeingRecorded());
+ macroManager.toggleMacroRecord(null, macroInstructionIdToFactory);
+ Assert.assertFalse(macroManager.isRecording());
+
+ macroManager.playbackLastMacro(null, playbackContext);
+ Assert.assertEquals("macro1", playbackContext.buffer.toString());
+ }
+
+ @Test
+ public void testAddMacroInstructionPriority1() throws Exception {
+ MacroManager macroManager = new MacroManager();
+ Map<String, IMacroInstructionFactory> macroInstructionIdToFactory = makeMacroInstructionIdToFactory();
+ PlaybackContext playbackContext = new PlaybackContext(macroInstructionIdToFactory);
+ macroManager.toggleMacroRecord(null, macroInstructionIdToFactory);
+ Assert.assertTrue(macroManager.isRecording());
+ Object ev = new Integer(1);
+ macroManager.addMacroInstruction(new DummyMacroInstruction("macro1"), ev, 1);
+ Assert.assertEquals(1, macroManager.getLenOfMacroBeingRecorded());
+ macroManager.addMacroInstruction(new DummyMacroInstruction("macro2"), ev, 2); // will replace it
+ Assert.assertEquals(1, macroManager.getLenOfMacroBeingRecorded());
+ macroManager.toggleMacroRecord(null, macroInstructionIdToFactory);
+ Assert.assertFalse(macroManager.isRecording());
+
+ macroManager.playbackLastMacro(null, playbackContext);
+ Assert.assertEquals("macro2", playbackContext.buffer.toString());
+ }
+
+ @Test
+ public void testMacroManagerSaveRestore() throws Exception {
+ File root = folder.getRoot();
+ MacroManager macroManager = new MacroManager(root);
+ Map<String, IMacroInstructionFactory> macroInstructionIdToFactory = makeMacroInstructionIdToFactory();
+ createMacroWithOneDummyMacroInstruction(macroManager, macroInstructionIdToFactory);
+ String[] macroNames = listTemporaryMacros(root);
+ Assert.assertEquals(1, macroNames.length);
+
+ // Create a new macroManager (to force getting from the disk).
+ macroManager = new MacroManager(root);
+ PlaybackContext playbackContext = new PlaybackContext(macroInstructionIdToFactory);
+ macroManager.playbackLastMacro(null, playbackContext);
+ Assert.assertEquals("macro1", playbackContext.buffer.toString());
+ }
+
+ @Test
+ public void testMacroManagerMaxNumberOfMacros() throws Exception {
+ File root = folder.getRoot();
+ MacroManager macroManager = new MacroManager(root);
+ macroManager.setMaxNumberOfTemporaryMacros(2);
+ Map<String, IMacroInstructionFactory> macroInstructionIdToFactory = makeMacroInstructionIdToFactory();
+
+ createMacroWithOneDummyMacroInstruction(macroManager, macroInstructionIdToFactory);
+
+ String[] macroNames1 = listTemporaryMacros(root);
+ Assert.assertEquals(macroNames1.length, 1);
+
+ // Sleep to make sure that the time of the file will be different
+ // (otherwise, if it runs too fast, the same time could be applied to
+ // the first, second and last file, in which case we may remove the
+ // wrong one).
+ sleepABit();
+ createMacroWithOneDummyMacroInstruction(macroManager, macroInstructionIdToFactory);
+
+ String[] macroNames2 = listTemporaryMacros(root);
+ Assert.assertEquals(2, macroNames2.length);
+ HashSet<Long> times = new HashSet<>();
+ List<PathAndTime> macrosPathAndTime = macroManager.listTemporaryMacrosPathAndTime(root);
+ for (PathAndTime pathAndTime : macrosPathAndTime) {
+ times.add(pathAndTime.fLastModified);
+ }
+ Assert.assertEquals(2, times.size());
+
+ // Now, creating a new one removes the old one
+ sleepABit();
+ createMacroWithOneDummyMacroInstruction(macroManager, macroInstructionIdToFactory);
+ macrosPathAndTime = macroManager.listTemporaryMacrosPathAndTime(root);
+
+ String[] macroNames3 = listTemporaryMacros(root);
+ Assert.assertEquals(2, macroNames3.length);
+
+ for (PathAndTime pathAndTime : macrosPathAndTime) {
+ times.add(pathAndTime.fLastModified);
+ }
+
+ Assert.assertEquals(3, times.size());
+
+ assertNotContains(Arrays.asList(macroNames3), macroNames1[0]);
+ }
+
+ private void assertNotContains(Collection<String> list, String name) {
+ if (list.contains(name)) {
+ StringBuffer stringBuffer = new StringBuffer();
+ stringBuffer.append("Did not expect: ").append(name).append("\nTo be in:\n");
+ for (String string : list) {
+ stringBuffer.append(string).append("\n");
+ }
+ Assert.fail(stringBuffer.toString());
+ }
+
+ }
+
+ private void sleepABit() {
+ synchronized (this) {
+ try {
+ this.wait(1000); // Sleep a full second to make sure that we have a new timestamp
+ // on files to make test less brittle (not all systems have
+ // a good precision).
+ } catch (InterruptedException e) {
+ // Ignore in this case
+ }
+ }
+
+ }
+
+ protected String[] listTemporaryMacros(File root) {
+ String[] files = root.list(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".js") && name.startsWith("temp_macro");
+ }
+ });
+ return files;
+ }
+
+ protected void createMacroWithOneDummyMacroInstruction(MacroManager macroManager,
+ Map<String, IMacroInstructionFactory> macroInstructionIdToFactory) throws CancelMacroRecordingException {
+ macroManager.toggleMacroRecord(null, macroInstructionIdToFactory);
+ macroManager.addMacroInstruction(new DummyMacroInstruction("macro1"));
+ macroManager.toggleMacroRecord(null, macroInstructionIdToFactory);
+ }
+
+ private Map<String, IMacroInstructionFactory> makeMacroInstructionIdToFactory() {
+ Map<String, IMacroInstructionFactory> macroInstructionIdToFactory = new HashMap<>();
+ macroInstructionIdToFactory.put("dummy", new IMacroInstructionFactory() {
+
+ @Override
+ public IMacroInstruction create(Map<String, String> stringMap) {
+ if (stringMap.size() != 2) {
+ throw new AssertionError("Expected map size to be 2. Found: " + stringMap.size());
+ }
+ if (!stringMap.get("dummyKey").equals("dummyValue")) {
+ throw new AssertionError("Did not find dummyKey->dummyValue mapping.");
+ }
+ if (stringMap.get("name") == null) {
+ throw new AssertionError("Expected name to be defined.");
+ }
+
+ return new DummyMacroInstruction(stringMap.get("name"));
+ }
+ });
+ return macroInstructionIdToFactory;
+ }
+
+}