diff --git a/README.md b/README.md
index c250a8e81..f8a5b8b7d 100644
--- a/README.md
+++ b/README.md
@@ -1,82 +1,17 @@
-Kotlin for Eclipse
-==============
-
-[](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
-
-Welcome to Kotlin for Eclipse project! Some handy links:
-
- * [Kotlin Site](http://kotlinlang.org/)
- * [Getting Started Guide](http://kotlinlang.org/docs/tutorials/getting-started-eclipse.html)
- * [Kotlin on Eclipse Marketplace](https://marketplace.eclipse.org/content/kotlin-plugin-eclipse)
- * Issue Tracker: [File New Issue](https://youtrack.jetbrains.com/newIssue?project=KE&clearDraft=true), [All Open Issues](https://youtrack.jetbrains.com/issues/KE?q=%23Unresolved)
- * [Kotlin Blog](http://blog.jetbrains.com/kotlin/)
- * [Forum](https://discuss.kotlinlang.org/)
- * [TeamCity CI build](https://teamcity.jetbrains.com/viewType.html?buildTypeId=Kotlin_EclipsePlugin)
- * [Follow Kotlin on Twitter](https://twitter.com/kotlin)
-
-### Installation
-
-To give it a try you will need a clean installation of Eclipse Neon or newer. The Kotlin plugin is available from the Eclipse Marketplace. The easiest way to install the Kotlin plugin is to **drag-and-drop this button into a running Eclipse window**:
-
-
-
-Alternatively, you can use *Help -> Eclipse Marketplaceā¦* menu, or the following update site:
-
- https://dl.bintray.com/jetbrains/kotlin/eclipse-plugin/last/
-
-### Building and Development
-
-*Eclipse IDE for Eclipse Committers* is the recommended way to build and develop the `kotlin-eclipse` project. Eclipse [Oxygen 4.7](https://www.eclipse.org/downloads/packages/eclipse-ide-eclipse-committers/oxygenr) is used so far.
-
-In order to start development in Eclipse:
- - Install the [AspectJ Eclipse plug-in for Eclipse 4.7](http://www.eclipse.org/ajdt/downloads/index.php). To install AJDT 2.2.4 use the following update site:
-
- http://download.eclipse.org/tools/ajdt/47/dev/update
-
- - Since Kotlin plugin contains code written in Kotlin itself, you will also need a Kotlin plugin to build the project in Eclipse. To install the Kotlin Eclipse plugin use the following update site:
-
- https://teamcity.jetbrains.com/guestAuth/repository/download/Kotlin_EclipsePlugin/bootstrap.tcbuildtag/
-
- - Since Kotlin plugin uses weaving, you need to launch the project with weaving enabled. Installation of Equinox Weaving Launcher will add two additional launch configurations types for running plugin and for testing. To install the Equinox Weaving Launcher you can use the following update site:
-
- http://download.scala-ide.org/plugins/equinox-weaving-launcher/releases/site/
-
- - Import plugin projects from the cloned repository into your workspace
-
- File -> Import -> Existing Projects into Workspace
-
- - Using the command line, run gradle build to download the Kotlin compiler. It will be used as a bundled compiler in built plugin and as a library during development.
-
- cd {repository}/kotlin-bundled-compiler
- ./gradlew clean getBundled
- or in Windows environment:
-
- cd {repository}\kotlin-bundled-compiler
- gradlew.bat clean getBundled
-
- - Run another instance of Eclipse with the Kotlin plugin inside
-
- kotlin-eclipse-ui -> Run As -> Eclipse Weaving enabled Eclipse Application
-
-Building from the command line is also available (Note that Maven **3.0.5** is required):
-
- cd {repository}
- mvn install
-
-### Eclipse update sites
-
-Latest stable release:
-
- https://dl.bintray.com/jetbrains/kotlin/eclipse-plugin/last/
-
-Any previously released version (replace *:version* with the version number):
-
- https://dl.bintray.com/jetbrains/kotlin/eclipse-plugin/:version/
-
-Nightly build:
-
- https://teamcity.jetbrains.com/guestAuth/repository/download/Kotlin_EclipsePlugin/.lastSuccessful/
-
-### Kotlin Eclipse Plugin Developer Documentation
-
-See basic developer documentation [here](https://github.com/JetBrains/kotlin-eclipse/blob/master/docs/dev-documentation.md)
+Enhanced Kotlin for Eclipse
+==============
+
+This plugin based on [JetBrains Kotlin plugin](https://github.com/JetBrains/kotlin-eclipse) and contains small enhancements. These enhancements mostly related to adaptations for latest versions ov Java, Eclipse and so on.
+
+Update sites description
+
+Update-site URL | Description
+----------------|------------
+https://s3.eu-central-1.amazonaws.com/github.bvfalcon/kotlin-eclipse/eclipse-releases/2021-09/ | Last version Kotlin for Eclipse 2021-09
+https://s3.eu-central-1.amazonaws.com/github.bvfalcon/kotlin-eclipse/eclipse-releases/2021-06/ | Last version Kotlin for Eclipse 2021-06
+https://s3.eu-central-1.amazonaws.com/github.bvfalcon/kotlin-eclipse/eclipse-releases/2021-03/ | Last version Kotlin for Eclipse 2021-03
+https://s3.eu-central-1.amazonaws.com/github.bvfalcon/kotlin-eclipse/eclipse-releases/2020-12/ | Last version Kotlin for Eclipse 2020-12
+https://s3.eu-central-1.amazonaws.com/github.bvfalcon/kotlin-eclipse/eclipse-releases/2020-03/ | Last version Kotlin for Eclipse 2020-03
+https://s3.eu-central-1.amazonaws.com/github.bvfalcon/kotlin-eclipse/versions/0.8.20/ | Version 0.8.20 Kotlin for Eclipse 2020-03
+
+
diff --git a/kotlin-bundled-compiler/.classpath b/kotlin-bundled-compiler/.classpath
deleted file mode 100644
index 80949bebc..000000000
--- a/kotlin-bundled-compiler/.classpath
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/kotlin-bundled-compiler/.project b/kotlin-bundled-compiler/.project
deleted file mode 100644
index 002a00b34..000000000
--- a/kotlin-bundled-compiler/.project
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
- kotlin-bundled-compiler
-
-
-
-
-
- org.jetbrains.kotlin.ui.kotlinBuilder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- org.eclipse.pde.ManifestBuilder
-
-
-
-
- org.eclipse.pde.SchemaBuilder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
- org.eclipse.pde.PluginNature
- org.jetbrains.kotlin.core.kotlinNature
-
-
-
- kotlin_bin
- 2
- org.jetbrains.kotlin.core.filesystem:/kotlin-bundled-compiler/kotlin_bin
-
-
-
diff --git a/kotlin-bundled-compiler/.settings/org.eclipse.jdt.core.prefs b/kotlin-bundled-compiler/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index 9a57a84d6..000000000
--- a/kotlin-bundled-compiler/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,297 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.kt
-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.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=16
-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=0
-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=true
-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=space
-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=true
-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
diff --git a/kotlin-bundled-compiler/.settings/org.eclipse.jdt.ui.prefs b/kotlin-bundled-compiler/.settings/org.eclipse.jdt.ui.prefs
deleted file mode 100644
index bddb247ef..000000000
--- a/kotlin-bundled-compiler/.settings/org.eclipse.jdt.ui.prefs
+++ /dev/null
@@ -1,3 +0,0 @@
-eclipse.preferences.version=1
-formatter_profile=_Kotlin
-formatter_settings_version=12
diff --git a/kotlin-bundled-compiler/META-INF/MANIFEST.MF b/kotlin-bundled-compiler/META-INF/MANIFEST.MF
index c491979ba..4db053701 100644
--- a/kotlin-bundled-compiler/META-INF/MANIFEST.MF
+++ b/kotlin-bundled-compiler/META-INF/MANIFEST.MF
@@ -2,29 +2,44 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Bundled Kotlin Compiler
Bundle-SymbolicName: org.jetbrains.kotlin.bundled-compiler;singleton:=true
-Bundle-Version: 0.8.21.qualifier
+Bundle-Version: 1.6.21.qualifier
Bundle-Vendor: JetBrains
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ClassPath: .,
+ lib/ide-common.jar,
lib/kotlin-compiler.jar,
- lib/intellij-core-analysis.jar,
+ lib/ide-dependencies.jar,
lib/kotlin-stdlib.jar,
lib/kotlin-plugin-parts.jar,
lib/kotlin-script-runtime.jar,
lib/kotlin-scripting-compiler.jar,
+ lib/kotlin-formatter.jar,
+ lib/kotlin-common.jar,
+ lib/kotlin-core.jar,
+ lib/kotlin-idea.jar,
+ lib/kotlin-j2k-old.jar,
+ lib/kotlin-j2k-new.jar,
+ lib/kotlin-j2k-idea.jar,
+ lib/kotlin-j2k-services.jar,
+ lib/kotlin-frontend-independent.jar,
lib/kotlin-reflect.jar,
../kotlin-eclipse-ui-test/lib/gson-2.3.1.jar,
- lib/ide-dependencies.jar,
lib/annotations-13.0.jar,
lib/kotlin-scripting-compiler-impl.jar,
lib/kotlin-scripting-common.jar,
lib/kotlin-scripting-jvm.jar,
- lib/ide-common.jar
-Export-Package:
+ lib/kotlinx-coroutines-core.jar,
+ lib/intellij-core-analysis-deprecated.jar
+Export-Package: com.google.common.collect,
com.intellij,
+ org.jetbrains.kotlin.idea.util.application,
+ org.jetbrains.kotlin.idea.caches.resolve,
+ org.jetbrains.kotlin.idea.core.util,
+ org.jetbrains.kotlin.nj2k,
+ org.jetbrains.kotlin.idea.j2k,
+ org.jetbrains.kotlin.nj2k.postProcessing,
com.intellij.codeInsight,
com.intellij.codeInsight.completion.scope,
- com.intellij.codeInsight.daemon,
com.intellij.codeInsight.folding,
com.intellij.codeInsight.folding.impl,
com.intellij.codeInsight.javadoc,
@@ -37,7 +52,6 @@ Export-Package:
com.intellij.ide,
com.intellij.ide.highlighter,
com.intellij.ide.plugins,
- com.intellij.ide.plugins.cl,
com.intellij.ide.util,
com.intellij.injected.editor,
com.intellij.lang,
@@ -197,15 +211,18 @@ Export-Package:
kotlin.reflect.full,
kotlin.reflect.jvm.internal.impl.load.kotlin,
kotlin.script.dependencies,
+ kotlin.script.experimental.annotations,
kotlin.script.experimental.api,
kotlin.script.experimental.dependencies,
kotlin.script.experimental.host,
kotlin.script.experimental.jvm,
+ kotlin.script.experimental.util,
kotlin.script.extensions,
kotlin.script.templates,
kotlin.script.templates.standard,
kotlin.sequences,
kotlin.text,
+ kotlinx.coroutines,
org.jetbrains.annotations,
org.jetbrains.kotlin,
org.jetbrains.kotlin.analyzer,
@@ -259,6 +276,7 @@ Export-Package:
org.jetbrains.kotlin.descriptors,
org.jetbrains.kotlin.descriptors.annotations,
org.jetbrains.kotlin.descriptors.impl,
+ org.jetbrains.kotlin.descriptors.java,
org.jetbrains.kotlin.diagnostics,
org.jetbrains.kotlin.diagnostics.rendering,
org.jetbrains.kotlin.extensions,
@@ -345,6 +363,7 @@ Export-Package:
org.jetbrains.kotlin.resolve.lazy.data,
org.jetbrains.kotlin.resolve.lazy.declarations,
org.jetbrains.kotlin.resolve.lazy.descriptors,
+ org.jetbrains.kotlin.resolve.sam,
org.jetbrains.kotlin.resolve.scopes,
org.jetbrains.kotlin.resolve.scopes.receivers,
org.jetbrains.kotlin.resolve.scopes.utils,
diff --git a/kotlin-bundled-compiler/build.gradle.kts b/kotlin-bundled-compiler/build.gradle.kts
index 0fdf0016c..cdd8a9d6b 100644
--- a/kotlin-bundled-compiler/build.gradle.kts
+++ b/kotlin-bundled-compiler/build.gradle.kts
@@ -1,7 +1,7 @@
import com.intellij.buildsupport.dependencies.PackageListFromSimpleFile
+import com.intellij.buildsupport.resolve.http.HttpArtifact
+import com.intellij.buildsupport.resolve.http.HttpArtifactsResolver
import com.intellij.buildsupport.resolve.http.idea.IntellijIdeaArtifactsResolver
-import com.intellij.buildsupport.resolve.tc.kotlin.CommonIDEArtifactsResolver
-import com.intellij.buildsupport.resolve.tc.kotlin.KotlinCompilerTCArtifactsResolver
import com.intellij.buildsupport.utils.FileUtils
apply(plugin = "base")
@@ -11,13 +11,16 @@ val teamcityBaseUrl ="https://teamcity.jetbrains.com"
val ideaSdkUrl = "https://www.jetbrains.com/intellij-repository/releases/com/jetbrains/intellij/idea"
// properties that might/should be modifiable
-val kotlinCompilerTcBuildId: String = project.findProperty("kotlinCompilerTcBuildId") as String? ?: "3282462"
-val kotlinCompilerVersion: String = project.findProperty("kotlinCompilerVersion") as String? ?: "1.4.0"
-val kotlinxVersion: String = project.findProperty("kolinxVersion") as String? ?: "1.3.1"
+
+//val kotlinCompilerTcBuildId: String = project.findProperty("kotlinCompilerTcBuildId") as String? ?: "3546752"
+val kotlinPluginUpdateId = project.findProperty("kotlinPluginUpdateId") as String? ?: "169248" // Kotlin Plugin 1.6.21 for Idea 2021.3
+
+val kotlinCompilerVersion: String = project.findProperty("kotlinCompilerVersion") as String? ?: "1.6.21"
+val kotlinxVersion: String = project.findProperty("kolinxVersion") as String? ?: "1.5.2"
val tcArtifactsPath: String = project.findProperty("tcArtifactsPath") as String? ?: ""
-val ideaVersion: String = project.findProperty("ideaVersion") as String? ?: "193.6494.35"
-val kotlinIdeaCompatibleVersionMinor: String = project.findProperty("kotlinIdeaCompatibleVersionMinor") as String? ?: "2019.3"
-val ignoreSources: Boolean = project.hasProperty("ignoreSources")
+val ideaVersion: String = project.findProperty("ideaVersion") as String? ?: "213.5744.223" //Idea 2021.3
+val kotlinIdeaCompatibleVersionMinor: String = project.findProperty("kotlinIdeaCompatibleVersionMinor") as String? ?: "2021.3"
+val ignoreSources: Boolean = true//project.hasProperty("ignoreSources")
//directories
val testDataDir = file("${projectDir.parentFile}/kotlin-eclipse-ui-test/common_testData")
@@ -33,14 +36,21 @@ val libDir = if (teamCityWorkingDir != null) file("$teamCityWorkingDir/lib") els
val localTCArtifacts: Boolean = tcArtifactsPath.isNotBlank()
val downloadDir = if(localTCArtifacts) file(tcArtifactsPath) else file("$libDir/$downloadDirName")
-val tcArtifactsResolver = KotlinCompilerTCArtifactsResolver(teamcityBaseUrl,
+/*val tcArtifactsResolver = KotlinCompilerTCArtifactsResolver(teamcityBaseUrl,
project.hasProperty("lastSuccessfulBuild"),
kotlinCompilerTcBuildId,
kotlinCompilerVersion,
- kotlinIdeaCompatibleVersionMinor)
+ kotlinIdeaCompatibleVersionMinor)*/
+
+HttpArtifactsResolver.getProxyProps()["https.proxyHost"] = project.findProperty("https.proxyHost") ?: System.getProperty("https.proxyHost")
+HttpArtifactsResolver.getProxyProps()["https.proxyPort"] = project.findProperty("https.proxyPort") ?: System.getProperty("https.proxyPort")
+HttpArtifactsResolver.getProxyProps()["https.proxyUser"] = project.findProperty("https.proxyUser") ?: System.getProperty("https.proxyUser")
+HttpArtifactsResolver.getProxyProps()["https.proxyPassword"] = project.findProperty("https.proxyPassword") ?: System.getProperty("https.proxyPassword")
val ideaArtifactsResolver = IntellijIdeaArtifactsResolver(ideaSdkUrl, ideaVersion)
+val kotlinPluginArtifactsResolver = HttpArtifactsResolver("https://plugins.jetbrains.com")
+val tempKotlinHttpArtifact = HttpArtifact("plugin/download?rel=true&updateId=$kotlinPluginUpdateId")
tasks.withType {
gradleVersion = "5.5.1"
@@ -67,6 +77,12 @@ tasks.named("clean") {
}
}
+val deleteLibrariesFromLibFolder by tasks.registering {
+ doFirst {
+ libDir.listFiles()?.filter { it.isFile }?.forEach { it.deleteRecursively() }
+ }
+}
+
val downloadTestData by tasks.registering {
val locallyDownloadedTestDataFile by extra {
if(localTCArtifacts){
@@ -77,16 +93,15 @@ val downloadTestData by tasks.registering {
}
doLast {
- if (!localTCArtifacts) {
- tcArtifactsResolver.downloadTo(tcArtifactsResolver.KOTLIN_TEST_DATA_ZIP, locallyDownloadedTestDataFile)
+ //TODO can we get the test data from somewhere?
+ if (!localTCArtifacts && !locallyDownloadedTestDataFile.exists()) {
+ //tcArtifactsResolver.downloadTo(tcArtifactsResolver.KOTLIN_TEST_DATA_ZIP, locallyDownloadedTestDataFile)
}
- copy {
+ /*copy {
from(zipTree(locallyDownloadedTestDataFile))
into(testDataDir)
- }
-
- locallyDownloadedTestDataFile.delete()
+ }*/
}
}
@@ -96,14 +111,18 @@ val downloadTestFrameworkDependencies by tasks.registering(Copy::class) {
}
val downloadKotlinCompilerPluginAndExtractSelectedJars by tasks.registering {
+ dependsOn(deleteLibrariesFromLibFolder)
+
+ val kotlinDownloadDir = file("$downloadDir/kotlin-$kotlinCompilerVersion/$kotlinIdeaCompatibleVersionMinor")
val locallyDownloadedCompilerFile by extra {
- file(downloadDir).listFiles()?.firstOrNull { it.name.startsWith("kotlin-plugin-") }
- ?: file("$downloadDir/kotlin-plugin.zip")
+ file(kotlinDownloadDir).listFiles()?.firstOrNull { it.name.startsWith("kotlin-plugin-") }
+ ?: file("$kotlinDownloadDir/kotlin-plugin.zip")
}
doLast {
- if (!localTCArtifacts) {
- tcArtifactsResolver.downloadTo(tcArtifactsResolver.KOTLIN_PLUGIN_ZIP, locallyDownloadedCompilerFile)
+ if (!localTCArtifacts && !locallyDownloadedCompilerFile.exists()) {
+ kotlinPluginArtifactsResolver.downloadTo(tempKotlinHttpArtifact, locallyDownloadedCompilerFile)
+ //tcArtifactsResolver.downloadTo(tcArtifactsResolver.KOTLIN_PLUGIN_ZIP, locallyDownloadedCompilerFile)
}
copy {
@@ -111,6 +130,15 @@ val downloadKotlinCompilerPluginAndExtractSelectedJars by tasks.registering {
setIncludes(setOf("Kotlin/lib/kotlin-plugin.jar",
"Kotlin/lib/ide-common.jar",
+ "Kotlin/lib/kotlin-core.jar",
+ "Kotlin/lib/kotlin-idea.jar",
+ "Kotlin/lib/kotlin-common.jar",
+ "Kotlin/lib/kotlin-j2k-old.jar",
+ "Kotlin/lib/kotlin-j2k-new.jar",
+ "Kotlin/lib/kotlin-j2k-idea.jar",
+ "Kotlin/lib/kotlin-j2k-services.jar",
+ "Kotlin/lib/kotlin-frontend-independent.jar",
+ "Kotlin/lib/kotlin-formatter.jar",
"Kotlin/kotlinc/lib/kotlin-compiler.jar",
"Kotlin/kotlinc/lib/kotlin-stdlib.jar",
"Kotlin/kotlinc/lib/kotlin-reflect.jar",
@@ -141,8 +169,8 @@ val extractPackagesFromPlugin by tasks.registering(Jar::class) {
dependsOn(downloadKotlinCompilerPluginAndExtractSelectedJars)
from(zipTree("$libDir/kotlin-plugin.jar"))
- destinationDir = libDir
- archiveName = "kotlin-plugin-parts.jar"
+ destinationDirectory.set(libDir)
+ archiveFileName.set("kotlin-plugin-parts.jar")
include("**")
exclude("com/intellij/util/**")
@@ -152,15 +180,18 @@ val extractPackagesFromPlugin by tasks.registering(Jar::class) {
}
val downloadIntellijCoreAndExtractSelectedJars by tasks.registering {
- val locallyDownloadedIntellijCoreFile by extra { file("$downloadDir/intellij-core.zip") }
+ dependsOn(deleteLibrariesFromLibFolder)
+ val ideaDownloadDir = file("$downloadDir/idea-$ideaVersion")
+ val locallyDownloadedIntellijCoreFile by extra { file("$ideaDownloadDir/intellij-core.zip") }
doLast {
- ideaArtifactsResolver.downloadTo(ideaArtifactsResolver.INTELLIJ_CORE_ZIP, locallyDownloadedIntellijCoreFile)
-
+ if(!locallyDownloadedIntellijCoreFile.exists()) {
+ ideaArtifactsResolver.downloadTo(ideaArtifactsResolver.INTELLIJ_CORE_ZIP, locallyDownloadedIntellijCoreFile)
+ }
copy {
from(zipTree(locallyDownloadedIntellijCoreFile))
- setIncludes(setOf("intellij-core.jar", "intellij-core-analysis.jar"))
+ setIncludes(setOf("intellij-core.jar", "intellij-core-analysis-deprecated.jar"))
includeEmptyDirs = false
@@ -170,18 +201,21 @@ val downloadIntellijCoreAndExtractSelectedJars by tasks.registering {
}
val downloadIdeaDistributionZipAndExtractSelectedJars by tasks.registering {
- val locallyDownloadedIdeaZipFile by extra { file("$downloadDir/ideaIC.zip") }
- val chosenJars by extra { setOf("openapi",
- "platform-util-ui",
+ dependsOn(deleteLibrariesFromLibFolder)
+ val ideaDownloadDir = file("$downloadDir/idea-$ideaVersion")
+ val locallyDownloadedIdeaZipFile by extra { file("$ideaDownloadDir/ideaIC.zip") }
+ val chosenJars by extra { setOf(//"openapi",
+ //"platform-util-ui",
"util",
"idea",
- "trove4j",
+ //"trove4j",
"platform-api",
"platform-impl") }
doLast {
- ideaArtifactsResolver.downloadTo(ideaArtifactsResolver.IDEA_IC_ZIP, locallyDownloadedIdeaZipFile)
-
+ if(!locallyDownloadedIdeaZipFile.exists()) {
+ ideaArtifactsResolver.downloadTo(ideaArtifactsResolver.IDEA_IC_ZIP, locallyDownloadedIdeaZipFile)
+ }
copy {
from(zipTree(locallyDownloadedIdeaZipFile))
@@ -204,7 +238,7 @@ val extractSelectedFilesFromIdeaJars by tasks.registering {
val packages by extra {
/*new PackageListFromManifest("META-INF/MANIFEST.MF"),*/
- PackageListFromSimpleFile("referencedPackages.txt").pathsToInclude
+ PackageListFromSimpleFile(file("referencedPackages.txt").path).pathsToInclude
}
val extractDir by extra { file("$downloadDir/dependencies") }
@@ -228,8 +262,8 @@ val createIdeDependenciesJar by tasks.registering(Jar::class) {
val extractDir: File by extractSelectedFilesFromIdeaJars.get().extra
from(extractDir)
- destinationDir = libDir
- archiveName = "ide-dependencies.jar"
+ destinationDirectory.set(libDir)
+ archiveFileName.set("ide-dependencies.jar")
manifest {
attributes(mapOf("Built-By" to "JetBrains",
@@ -254,8 +288,13 @@ val downloadIdeaAndKotlinCompilerSources by tasks.registering {
val locallyDownloadedIdeaSourcesFile by extra { file("$downloadDir/idea-sdk-sources.jar") }
doLast {
- tcArtifactsResolver.downloadTo(tcArtifactsResolver.KOTLIN_COMPILER_SOURCES_JAR, locallyDownloadedKotlinCompilerSourcesFile)
- ideaArtifactsResolver.downloadTo(ideaArtifactsResolver.IDEA_IC_SOURCES_JAR, locallyDownloadedIdeaSourcesFile)
+ if(!locallyDownloadedKotlinCompilerSourcesFile.exists()) {
+ //TODO can we get the sources from somewhere?
+ //tcArtifactsResolver.downloadTo(tcArtifactsResolver.KOTLIN_COMPILER_SOURCES_JAR, locallyDownloadedKotlinCompilerSourcesFile)
+ }
+ if(!locallyDownloadedIdeaSourcesFile.exists()) {
+ ideaArtifactsResolver.downloadTo(ideaArtifactsResolver.IDEA_IC_SOURCES_JAR, locallyDownloadedIdeaSourcesFile)
+ }
}
}
@@ -268,20 +307,18 @@ val repackageIdeaAndKotlinCompilerSources by tasks.registering(Zip::class) {
from(zipTree(locallyDownloadedKotlinCompilerSourcesFile))
from(zipTree(locallyDownloadedIdeaSourcesFile))
- destinationDir = libDir
- archiveName = "kotlin-compiler-sources.jar"
+ destinationDirectory.set(libDir)
+ archiveFileName.set("kotlin-compiler-sources.jar")
}
val downloadBundled by tasks.registering {
if (localTCArtifacts) {
- dependsOn(downloadKotlinCompilerPluginAndExtractSelectedJars,
- extractPackagesFromPlugin,
+ dependsOn(extractPackagesFromPlugin,
downloadIntellijCoreAndExtractSelectedJars,
createIdeDependenciesJar,
downloadKotlinxLibraries)
} else {
- dependsOn(downloadKotlinCompilerPluginAndExtractSelectedJars,
- extractPackagesFromPlugin,
+ dependsOn(extractPackagesFromPlugin,
downloadIntellijCoreAndExtractSelectedJars,
createIdeDependenciesJar,
downloadKotlinxLibraries)
diff --git a/kotlin-bundled-compiler/build.properties b/kotlin-bundled-compiler/build.properties
index 1052121f8..3843203b4 100644
--- a/kotlin-bundled-compiler/build.properties
+++ b/kotlin-bundled-compiler/build.properties
@@ -35,8 +35,17 @@ bin.includes = META-INF/,\
lib/kotlin-scripting-jvm.jar,\
lib/kotlin-scripting-compiler-impl.jar,\
lib/kotlin-plugin-parts.jar,\
+ lib/kotlin-formatter.jar,\
+ lib/kotlin-common.jar,\
+ lib/kotlin-idea.jar,\
+ lib/kotlin-core.jar,\
+ lib/kotlin-j2k-old.jar,\
+ lib/kotlin-j2k-new.jar,\
+ lib/kotlin-j2k-idea.jar,\
+ lib/kotlin-j2k-services.jar,\
+ lib/kotlin-frontend-independent.jar,\
lib/ide-common.jar,\
- lib/intellij-core-analysis.jar
+ lib/intellij-core-analysis-deprecated.jar
src.includes = lib/
bin.excludes = lib/kotlin-compiler-sources.jar,\
lib/downloads/
diff --git a/kotlin-bundled-compiler/buildSrc/build.gradle b/kotlin-bundled-compiler/buildSrc/build.gradle
index 2cb2b707b..eef3ad4cd 100644
--- a/kotlin-bundled-compiler/buildSrc/build.gradle
+++ b/kotlin-bundled-compiler/buildSrc/build.gradle
@@ -9,14 +9,14 @@ repositories {
dependencies {
- compile 'org.jetbrains.teamcity:teamcity-rest-client:1.5.0'
+ implementation 'org.jetbrains.teamcity:teamcity-rest-client:1.5.0'
- testCompile('org.spockframework.spock:spock-core:spock-1.3') {
+ testImplementation('org.spockframework.spock:spock-core:spock-1.3') {
exclude module : 'groovy-all'
}
- testCompile 'com.github.stefanbirkner:system-rules:1.19.0'
- testCompile 'org.apache.commons:commons-lang3:3.8.1'
+ testImplementation 'com.github.stefanbirkner:system-rules:1.19.0'
+ testImplementation 'org.apache.commons:commons-lang3:3.8.1'
}
-test.enabled = false // otherwise integration tests will run always before the actual build
\ No newline at end of file
+test.enabled = false // otherwise integration tests will run always before the actual build
diff --git a/kotlin-bundled-compiler/buildSrc/src/main/groovy/com/intellij/buildsupport/dependencies/PackageList.groovy b/kotlin-bundled-compiler/buildSrc/src/main/groovy/com/intellij/buildsupport/dependencies/PackageList.groovy
index abef5442e..d50ec329e 100644
--- a/kotlin-bundled-compiler/buildSrc/src/main/groovy/com/intellij/buildsupport/dependencies/PackageList.groovy
+++ b/kotlin-bundled-compiler/buildSrc/src/main/groovy/com/intellij/buildsupport/dependencies/PackageList.groovy
@@ -2,7 +2,15 @@ package com.intellij.buildsupport.dependencies
abstract class PackageList {
List getPathsToInclude() {
- packageNames.collect { it.replace('.', '/') + '/*.class'}
+ List tempList = []
+ packageNames.forEach {
+ if(it.startsWith("custom:")) {
+ tempList.add(it.replace("custom:", ""))
+ } else {
+ tempList.add(it.replace('.', '/') + '/*.class')
+ }
+ }
+ return tempList
}
protected abstract List getPackageNames()
diff --git a/kotlin-bundled-compiler/buildSrc/src/main/groovy/com/intellij/buildsupport/resolve/http/HttpArtifactsResolver.groovy b/kotlin-bundled-compiler/buildSrc/src/main/groovy/com/intellij/buildsupport/resolve/http/HttpArtifactsResolver.groovy
index 36eac1980..8df349e85 100644
--- a/kotlin-bundled-compiler/buildSrc/src/main/groovy/com/intellij/buildsupport/resolve/http/HttpArtifactsResolver.groovy
+++ b/kotlin-bundled-compiler/buildSrc/src/main/groovy/com/intellij/buildsupport/resolve/http/HttpArtifactsResolver.groovy
@@ -5,11 +5,13 @@ import groovy.transform.TupleConstructor
@TupleConstructor(includeFields = true)
-abstract class HttpArtifactsResolver {
+class HttpArtifactsResolver {
// FIELDS =========================================================================================================
protected final String httpBaseUrl
+ static Map proxyProps = new HashMap<>()
+
// PUBLIC API =====================================================================================================
final void downloadTo(HttpArtifact httpArtifact, File outputFile) {
@@ -23,8 +25,16 @@ abstract class HttpArtifactsResolver {
private void downloadFileFromUrlInto(String fileURL, File destinationFile) {
destinationFile.parentFile.mkdirs()
- new AntBuilder().get(src: fileURL,
- dest: destinationFile,
- usetimestamp: true)
+ def ant = new AntBuilder()
+ if (!proxyProps.isEmpty() && proxyProps['https.proxyHost'] != null) {
+ if (proxyProps.get("https.proxyUser") == null) {
+ ant.setproxy(proxyHost: proxyProps['https.proxyHost'], proxyPort: proxyProps['https.proxyPort'])
+ } else {
+ ant.setproxy(proxyHost: proxyProps['https.proxyHost'], proxyPort: proxyProps['https.proxyPort'], proxyUser: proxyProps['https.proxyUser'], proxyPassword: proxyProps['https.proxyPassword'])
+ }
+ }
+ ant.get(src: fileURL,
+ dest: destinationFile,
+ usetimestamp: true)
}
}
diff --git a/kotlin-bundled-compiler/gradle/wrapper/gradle-wrapper.properties b/kotlin-bundled-compiler/gradle/wrapper/gradle-wrapper.properties
index 4b7e1f3d3..442d9132e 100644
--- a/kotlin-bundled-compiler/gradle/wrapper/gradle-wrapper.properties
+++ b/kotlin-bundled-compiler/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/kotlin-bundled-compiler/pom.xml b/kotlin-bundled-compiler/pom.xml
index 51d81f683..d18b59f6d 100644
--- a/kotlin-bundled-compiler/pom.xml
+++ b/kotlin-bundled-compiler/pom.xml
@@ -8,7 +8,7 @@
../pom.xml
kotlin.eclipse
kotlin.eclipse.plugin
- 0.8.21-SNAPSHOT
+ 1.6.21-SNAPSHOT
org.jetbrains.kotlin.bundled-compiler
@@ -22,7 +22,9 @@
org.jetbrains.kotlin
kotlin-maven-plugin
${kotlin.version}
-
+
+ 11
+
compile
@@ -33,6 +35,15 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 8
+ 8
+
+
\ No newline at end of file
diff --git a/kotlin-bundled-compiler/referencedPackages.txt b/kotlin-bundled-compiler/referencedPackages.txt
index 2198c7da0..b4e156c48 100644
--- a/kotlin-bundled-compiler/referencedPackages.txt
+++ b/kotlin-bundled-compiler/referencedPackages.txt
@@ -2,6 +2,7 @@
com.intellij.psi.codeStyle
com.intellij.psi.formatter
+com.intellij.openapi.components
com.intellij.openapi.options
com.intellij.application.options
com.intellij.application.options.codeStyle.properties
@@ -10,8 +11,14 @@ com.intellij.formatting.engine
com.intellij.util.containers
gnu.trove
com.intellij.openapi.util
+com.intellij.openapi.util.text
com.intellij.psi.codeStyle.arrangement
com.intellij.configurationStore
com.intellij.openapi.progress
-com.intellij.openapi.util
com.intellij.ui
+com.intellij.util.text
+custom:com/intellij/CodeStyleBundle.class
+custom:com/intellij/DynamicBundle.class
+custom:com/intellij/AbstractBundle.class
+custom:messages/CodeStyleBundle.*
+it.unimi.dsi.fastutil.objects
\ No newline at end of file
diff --git a/kotlin-eclipse-core/src/org/jetbrains/kotlin/core/model/KotlinNullableNotNullManager.kt b/kotlin-bundled-compiler/src/com/intellij/codeInsight/KotlinNullableNotNullManager.kt
similarity index 77%
rename from kotlin-eclipse-core/src/org/jetbrains/kotlin/core/model/KotlinNullableNotNullManager.kt
rename to kotlin-bundled-compiler/src/com/intellij/codeInsight/KotlinNullableNotNullManager.kt
index 762508103..3f1d91297 100644
--- a/kotlin-eclipse-core/src/org/jetbrains/kotlin/core/model/KotlinNullableNotNullManager.kt
+++ b/kotlin-bundled-compiler/src/com/intellij/codeInsight/KotlinNullableNotNullManager.kt
@@ -14,14 +14,14 @@
* limitations under the License.
*
*******************************************************************************/
-package org.jetbrains.kotlin.core.model
+package com.intellij.codeInsight
-import com.intellij.codeInsight.NullabilityAnnotationInfo
-import com.intellij.codeInsight.NullableNotNullManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiModifierListOwner
+import org.jetbrains.annotations.Nullable
+
// Dummy implementation. Will be changed to something more useful, when KE-277 is fixed.
class KotlinNullableNotNullManager(project: Project) : NullableNotNullManager(project) {
@@ -41,13 +41,27 @@ class KotlinNullableNotNullManager(project: Project) : NullableNotNullManager(pr
_nullables.addAll(annotations)
}
- override fun getDefaultNotNull(): String = "NotNull"
-
override fun getNotNulls(): List = _notNulls
+ override fun setDefaultNotNull(defaultNotNull: String) {
+ }
+
override fun getDefaultNullable(): String = "Nullable"
- override fun setDefaultNotNull(defaultNotNull: String) {
+ override fun getDefaultNotNull(): String {
+ return "NotNullable"
+ }
+
+ override fun getDefaultNullables(): MutableList {
+ return mutableListOf(defaultNullable)
+ }
+
+ override fun getDefaultNotNulls(): MutableList {
+ return mutableListOf(defaultNotNull)
+ }
+
+ override fun getAllDefaultAnnotations(): MutableList {
+ return (defaultNullables + defaultNotNulls).toMutableList()
}
override fun setNotNulls(vararg annotations: String) {
@@ -73,5 +87,14 @@ class KotlinNullableNotNullManager(project: Project) : NullableNotNullManager(pr
} ?: false
}
+ @Nullable
+ override fun getNullityDefault(
+ container: PsiModifierListOwner,
+ placeTargetTypes: Array,
+ context: PsiElement, superPackage: Boolean
+ ): NullabilityAnnotationInfo? {
+ return null
+ }
+
override fun isNullable(owner: PsiModifierListOwner, checkBases: Boolean) = !isNotNull(owner, checkBases)
}
\ No newline at end of file
diff --git a/kotlin-bundled-compiler/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java b/kotlin-bundled-compiler/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java
index 1c899848c..096b7ded0 100644
--- a/kotlin-bundled-compiler/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java
+++ b/kotlin-bundled-compiler/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java
@@ -2,4 +2,8 @@
public class ReformatCodeProcessor {
public static final String COMMAND_NAME = "dummy";
+
+ public static String getCommandName() {
+ return "Reformat Code";
+ }
}
diff --git a/kotlin-bundled-compiler/src/com/intellij/openapi/util/text/StringUtil.java b/kotlin-bundled-compiler/src/com/intellij/openapi/util/text/StringUtil.java
index 3a460bcb4..37fa79134 100644
--- a/kotlin-bundled-compiler/src/com/intellij/openapi/util/text/StringUtil.java
+++ b/kotlin-bundled-compiler/src/com/intellij/openapi/util/text/StringUtil.java
@@ -28,3015 +28,3020 @@
//TeamCity inherits StringUtil: do not add private constructors!!!
@SuppressWarnings("MethodOverridesStaticMethodOfSuperclass")
public class StringUtil extends StringUtilRt {
- private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.text.StringUtil");
+ private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.text.StringUtil");
- @SuppressWarnings("SpellCheckingInspection") private static final String VOWELS = "aeiouy";
- private static final Pattern EOL_SPLIT_KEEP_SEPARATORS = Pattern.compile("(?<=(\r\n|\n))|(?<=\r)(?=[^\n])");
- private static final Pattern EOL_SPLIT_PATTERN = Pattern.compile(" *(\r|\n|\r\n)+ *");
- private static final Pattern EOL_SPLIT_PATTERN_WITH_EMPTY = Pattern.compile(" *(\r|\n|\r\n) *");
- private static final Pattern EOL_SPLIT_DONT_TRIM_PATTERN = Pattern.compile("(\r|\n|\r\n)+");
+ @SuppressWarnings("SpellCheckingInspection") private static final String VOWELS = "aeiouy";
+ private static final Pattern EOL_SPLIT_KEEP_SEPARATORS = Pattern.compile("(?<=(\r\n|\n))|(?<=\r)(?=[^\n])");
+ private static final Pattern EOL_SPLIT_PATTERN = Pattern.compile(" *(\r|\n|\r\n)+ *");
+ private static final Pattern EOL_SPLIT_PATTERN_WITH_EMPTY = Pattern.compile(" *(\r|\n|\r\n) *");
+ private static final Pattern EOL_SPLIT_DONT_TRIM_PATTERN = Pattern.compile("(\r|\n|\r\n)+");
- @NotNull
- public static MergingCharSequence replaceSubSequence(@NotNull CharSequence charSeq, int start, int end, @NotNull CharSequence replacement) {
- return new MergingCharSequence(
- new MergingCharSequence(charSeq.subSequence(0, start), replacement),
- charSeq.subSequence(end, charSeq.length()));
- }
+ @NotNull
+ public static MergingCharSequence replaceSubSequence(@NotNull CharSequence charSeq, int start, int end, @NotNull CharSequence replacement) {
+ return new MergingCharSequence(
+ new MergingCharSequence(charSeq.subSequence(0, start), replacement),
+ charSeq.subSequence(end, charSeq.length()));
+ }
+
+ @Contract(value = "null -> null; !null->!null", pure = true)
+ public static String internEmptyString(String s) {
+ return s == null ? null : (s.isEmpty() ? "" : s);
+ }
+
+ private static class MyHtml2Text extends HTMLEditorKit.ParserCallback {
+ @NotNull private final StringBuilder myBuffer = new StringBuilder();
+ private final boolean myIsSkipStyleTag;
+
+ private boolean myIsStyleTagOpened;
+
+ private MyHtml2Text(boolean isSkipStyleTag) {
+ myIsSkipStyleTag = isSkipStyleTag;
+ }
+
+ public void parse(@NotNull Reader in) throws IOException {
+ myBuffer.setLength(0);
+ new ParserDelegator().parse(in, this, Boolean.TRUE);
+ }
+
+ @Override
+ public void handleText(@NotNull char[] text, int pos) {
+ if (!myIsStyleTagOpened) {
+ myBuffer.append(text);
+ }
+ }
+
+ @Override
+ public void handleStartTag(@NotNull HTML.Tag tag, MutableAttributeSet set, int i) {
+ if (myIsSkipStyleTag && "style".equals(tag.toString())) {
+ myIsStyleTagOpened = true;
+ }
+ handleTag(tag);
+ }
+
+ @Override
+ public void handleEndTag(@NotNull HTML.Tag tag, int pos) {
+ if (myIsSkipStyleTag && "style".equals(tag.toString())) {
+ myIsStyleTagOpened = false;
+ }
+ }
+
+ @Override
+ public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet set, int i) {
+ handleTag(tag);
+ }
+
+ private void handleTag(@NotNull HTML.Tag tag) {
+ if (tag.breaksFlow() && myBuffer.length() > 0) {
+ myBuffer.append(SystemProperties.getLineSeparator());
+ }
+ }
+
+ @NotNull
+ public String getText() {
+ return myBuffer.toString();
+ }
+ }
+
+ private static final MyHtml2Text html2TextParser = new MyHtml2Text(false);
+
+ public static final NotNullFunction QUOTER = new NotNullFunction() {
+ @Override
+ @NotNull
+ public String fun(String s) {
+ return "\"" + s + "\"";
+ }
+ };
+
+ public static final NotNullFunction SINGLE_QUOTER = new NotNullFunction() {
+ @Override
+ @NotNull
+ public String fun(String s) {
+ return "'" + s + "'";
+ }
+ };
+
+ @NotNull
+ @Contract(pure = true)
+ public static List getWordsInStringLongestFirst(@NotNull String find) {
+ List words = getWordsIn(find);
+ // hope long words are rare
+ Collections.sort(words, new Comparator() {
+ @Override
+ public int compare(@NotNull final String o1, @NotNull final String o2) {
+ return o2.length() - o1.length();
+ }
+ });
+ return words;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapePattern(@NotNull final String text) {
+ return replace(replace(text, "'", "''"), "{", "'{'");
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static Function createToStringFunction(@SuppressWarnings("unused") @NotNull Class cls) {
+ return new Function() {
+ @Override
+ public String fun(@NotNull T o) {
+ return o.toString();
+ }
+ };
+ }
+
+ @NotNull
+ public static final Function TRIMMER = new Function() {
+ @Nullable
+ @Override
+ public String fun(@Nullable String s) {
+ return trim(s);
+ }
+ };
+
+ // Unlike String.replace(CharSequence,CharSequence) does not allocate intermediate objects on non-match
+ // TODO revise when JDK9 arrives - its String.replace(CharSequence, CharSequence) is more optimized
+ @NotNull
+ @Contract(pure = true)
+ public static String replace(@NotNull String text, @NotNull String oldS, @NotNull String newS) {
+ return replace(text, oldS, newS, false);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String replaceIgnoreCase(@NotNull String text, @NotNull String oldS, @NotNull String newS) {
+ return replace(text, oldS, newS, true);
+ }
+
+ /**
+ * @deprecated Use {@link String#replace(char,char)} instead
+ */
+ @NotNull
+ @Contract(pure = true)
+ @Deprecated
+ public static String replaceChar(@NotNull String buffer, char oldChar, char newChar) {
+ return buffer.replace(oldChar, newChar);
+ }
+
+ @Contract(pure = true)
+ public static String replace(@NotNull final String text, @NotNull final String oldS, @NotNull final String newS, final boolean ignoreCase) {
+ if (text.length() < oldS.length()) return text;
+
+ StringBuilder newText = null;
+ int i = 0;
+
+ while (i < text.length()) {
+ final int index = ignoreCase? indexOfIgnoreCase(text, oldS, i) : text.indexOf(oldS, i);
+ if (index < 0) {
+ if (i == 0) {
+ return text;
+ }
+
+ newText.append(text, i, text.length());
+ break;
+ }
+ else {
+ if (newText == null) {
+ if (text.length() == oldS.length()) {
+ return newS;
+ }
+ newText = new StringBuilder(text.length() - i);
+ }
+
+ newText.append(text, i, index);
+ newText.append(newS);
+ i = index + oldS.length();
+ }
+ }
+ return newText != null ? newText.toString() : "";
+ }
+
+ @Contract(pure = true)
+ public static int indexOfIgnoreCase(@NotNull String where, @NotNull String what, int fromIndex) {
+ return indexOfIgnoreCase((CharSequence)where, what, fromIndex);
+ }
+
+ /**
+ * Implementation copied from {@link String#indexOf(String, int)} except character comparisons made case insensitive
+ */
+ @Contract(pure = true)
+ public static int indexOfIgnoreCase(@NotNull CharSequence where, @NotNull CharSequence what, int fromIndex) {
+ int targetCount = what.length();
+ int sourceCount = where.length();
+
+ if (fromIndex >= sourceCount) {
+ return targetCount == 0 ? sourceCount : -1;
+ }
+
+ if (fromIndex < 0) {
+ fromIndex = 0;
+ }
+
+ if (targetCount == 0) {
+ return fromIndex;
+ }
+
+ char first = what.charAt(0);
+ int max = sourceCount - targetCount;
+
+ for (int i = fromIndex; i <= max; i++) {
+ /* Look for first character. */
+ if (!charsEqualIgnoreCase(where.charAt(i), first)) {
+ //noinspection StatementWithEmptyBody,AssignmentToForLoopParameter
+ while (++i <= max && !charsEqualIgnoreCase(where.charAt(i), first)) ;
+ }
+
+ /* Found first character, now look at the rest of v2 */
+ if (i <= max) {
+ int j = i + 1;
+ int end = j + targetCount - 1;
+ //noinspection StatementWithEmptyBody
+ for (int k = 1; j < end && charsEqualIgnoreCase(where.charAt(j), what.charAt(k)); j++, k++) ;
+
+ if (j == end) {
+ /* Found whole string. */
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ }
+
+ @Contract(pure = true)
+ public static int indexOfIgnoreCase(@NotNull String where, char what, int fromIndex) {
+ int sourceCount = where.length();
+ for (int i = Math.max(fromIndex, 0); i < sourceCount; i++) {
+ if (charsEqualIgnoreCase(where.charAt(i), what)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ @Contract(pure = true)
+ public static int lastIndexOfIgnoreCase(@NotNull String where, char what, int fromIndex) {
+ for (int i = Math.min(fromIndex, where.length() - 1); i >= 0; i--) {
+ if (charsEqualIgnoreCase(where.charAt(i), what)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ @Contract(pure = true)
+ public static boolean containsIgnoreCase(@NotNull String where, @NotNull String what) {
+ return indexOfIgnoreCase(where, what, 0) >= 0;
+ }
+
+ @Contract(pure = true)
+ public static boolean endsWithIgnoreCase(@NotNull String str, @NotNull String suffix) {
+ return StringUtilRt.endsWithIgnoreCase(str, suffix);
+ }
+
+ @Contract(pure = true)
+ public static boolean startsWithIgnoreCase(@NotNull String str, @NotNull String prefix) {
+ return StringUtilRt.startsWithIgnoreCase(str, prefix);
+ }
+
+ @Contract(pure = true)
+ @NotNull
+ public static String stripHtml(@NotNull String html, boolean convertBreaks) {
+ if (convertBreaks) {
+ html = html.replaceAll("
", "\n\n");
+ }
+
+ return html.replaceAll("<(.|\n)*?>", "");
+ }
+
+ @Contract(value = "null -> null; !null -> !null", pure = true)
+ public static String toLowerCase(@Nullable final String str) {
+ return str == null ? null : str.toLowerCase();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String getPackageName(@NotNull String fqName) {
+ return getPackageName(fqName, '.');
+ }
+
+ /**
+ * Given a fqName returns the package name for the type or the containing type.
+ *
+ *
+ * - {@code java.lang.String} -> {@code java.lang}
+ * - {@code java.util.Map.Entry} -> {@code java.util.Map}
+ *
+ *
+ * @param fqName a fully qualified type name. Not supposed to contain any type arguments
+ * @param separator the separator to use. Typically '.'
+ * @return the package name of the type or the declarator of the type. The empty string if the given fqName is unqualified
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String getPackageName(@NotNull String fqName, char separator) {
+ int lastPointIdx = fqName.lastIndexOf(separator);
+ if (lastPointIdx >= 0) {
+ return fqName.substring(0, lastPointIdx);
+ }
+ return "";
+ }
+
+ @Contract(pure = true)
+ public static int getLineBreakCount(@NotNull CharSequence text) {
+ int count = 0;
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+ if (c == '\n') {
+ count++;
+ }
+ else if (c == '\r') {
+ if (i + 1 < text.length() && text.charAt(i + 1) == '\n') {
+ //noinspection AssignmentToForLoopParameter
+ i++;
+ }
+ count++;
+ }
+ }
+ return count;
+ }
+
+ @Contract(pure = true)
+ public static boolean containsLineBreak(@NotNull CharSequence text) {
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+ if (isLineBreak(c)) return true;
+ }
+ return false;
+ }
+
+ @Contract(pure = true)
+ public static boolean isLineBreak(char c) {
+ return c == '\n' || c == '\r';
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeLineBreak(@NotNull String text) {
+ StringBuilder buffer = new StringBuilder(text.length());
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+ switch (c) {
+ case '\n':
+ buffer.append("\\n");
+ break;
+ case '\r':
+ buffer.append("\\r");
+ break;
+ default:
+ buffer.append(c);
+ }
+ }
+ return buffer.toString();
+ }
+
+ @Contract(pure = true)
+ public static boolean endsWithLineBreak(@NotNull CharSequence text) {
+ int len = text.length();
+ return len > 0 && isLineBreak(text.charAt(len - 1));
+ }
+
+ @Contract(pure = true)
+ public static int lineColToOffset(@NotNull CharSequence text, int line, int col) {
+ int curLine = 0;
+ int offset = 0;
+ while (line != curLine) {
+ if (offset == text.length()) return -1;
+ char c = text.charAt(offset);
+ if (c == '\n') {
+ curLine++;
+ }
+ else if (c == '\r') {
+ curLine++;
+ if (offset < text.length() - 1 && text.charAt(offset + 1) == '\n') {
+ offset++;
+ }
+ }
+ offset++;
+ }
+ return offset + col;
+ }
+
+ @Contract(pure = true)
+ public static int offsetToLineNumber(@NotNull CharSequence text, int offset) {
+ LineColumn lineColumn = offsetToLineColumn(text, offset);
+ return lineColumn != null ? lineColumn.line : -1;
+ }
+
+ @Contract(pure = true)
+ public static LineColumn offsetToLineColumn(@NotNull CharSequence text, int offset) {
+ int curLine = 0;
+ int curLineStart = 0;
+ int curOffset = 0;
+ while (curOffset < offset) {
+ if (curOffset == text.length()) return null;
+ char c = text.charAt(curOffset);
+ if (c == '\n') {
+ curLine++;
+ curLineStart = curOffset + 1;
+ }
+ else if (c == '\r') {
+ curLine++;
+ if (curOffset < text.length() - 1 && text.charAt(curOffset + 1) == '\n') {
+ curOffset++;
+ }
+ curLineStart = curOffset + 1;
+ }
+ curOffset++;
+ }
+
+ return LineColumn.of(curLine, offset - curLineStart);
+ }
+
+ /**
+ * Classic dynamic programming algorithm for string differences.
+ */
+ @Contract(pure = true)
+ public static int difference(@NotNull String s1, @NotNull String s2) {
+ int[][] a = new int[s1.length()][s2.length()];
+
+ for (int i = 0; i < s1.length(); i++) {
+ a[i][0] = i;
+ }
+
+ for (int j = 0; j < s2.length(); j++) {
+ a[0][j] = j;
+ }
+
+ for (int i = 1; i < s1.length(); i++) {
+ for (int j = 1; j < s2.length(); j++) {
+
+ a[i][j] = Math.min(Math.min(a[i - 1][j - 1] + (s1.charAt(i) == s2.charAt(j) ? 0 : 1), a[i - 1][j] + 1), a[i][j - 1] + 1);
+ }
+ }
+
+ return a[s1.length() - 1][s2.length() - 1];
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String wordsToBeginFromUpperCase(@NotNull String s) {
+ return fixCapitalization(s, ourPrepositions, true);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String wordsToBeginFromLowerCase(@NotNull String s) {
+ return fixCapitalization(s, ourPrepositions, false);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String toTitleCase(@NotNull String s) {
+ return fixCapitalization(s, ArrayUtil.EMPTY_STRING_ARRAY, true);
+ }
+
+ @NotNull
+ private static String fixCapitalization(@NotNull String s, @NotNull String[] prepositions, boolean title) {
+ StringBuilder buffer = null;
+ for (int i = 0; i < s.length(); i++) {
+ char prevChar = i == 0 ? ' ' : s.charAt(i - 1);
+ char currChar = s.charAt(i);
+ if (!Character.isLetterOrDigit(prevChar) && prevChar != '\'') {
+ if (Character.isLetterOrDigit(currChar)) {
+ if (title || Character.isUpperCase(currChar)) {
+ int j = i;
+ for (; j < s.length(); j++) {
+ if (!Character.isLetterOrDigit(s.charAt(j))) {
+ break;
+ }
+ }
+ if (!title && j > i + 1 && !Character.isLowerCase(s.charAt(i + 1))) {
+ // filter out abbreviations like I18n, SQL and CSS
+ continue;
+ }
+ if (!isPreposition(s, i, j - 1, prepositions)) {
+ if (buffer == null) {
+ buffer = new StringBuilder(s);
+ }
+ buffer.setCharAt(i, title ? toUpperCase(currChar) : toLowerCase(currChar));
+ }
+ }
+ }
+ }
+ }
+ return buffer == null ? s : buffer.toString();
+ }
+
+ private static final String[] ourPrepositions = {
+ "a", "an", "and", "as", "at", "but", "by", "down", "for", "from", "if", "in", "into", "not", "of", "on", "onto", "or", "out", "over",
+ "per", "nor", "the", "to", "up", "upon", "via", "with"
+ };
+
+ @Contract(pure = true)
+ public static boolean isPreposition(@NotNull String s, int firstChar, int lastChar) {
+ return isPreposition(s, firstChar, lastChar, ourPrepositions);
+ }
+
+ @Contract(pure = true)
+ public static boolean isPreposition(@NotNull String s, int firstChar, int lastChar, @NotNull String[] prepositions) {
+ for (String preposition : prepositions) {
+ boolean found = false;
+ if (lastChar - firstChar + 1 == preposition.length()) {
+ found = true;
+ for (int j = 0; j < preposition.length(); j++) {
+ if (toLowerCase(s.charAt(firstChar + j)) != preposition.charAt(j)) {
+ found = false;
+ }
+ }
+ }
+ if (found) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static NotNullFunction escaper(final boolean escapeSlash, @Nullable final String additionalChars) {
+ return new NotNullFunction() {
+ @NotNull
+ @Override
+ public String fun(@NotNull String dom) {
+ final StringBuilder builder = new StringBuilder(dom.length());
+ escapeStringCharacters(dom.length(), dom, additionalChars, escapeSlash, builder);
+ return builder.toString();
+ }
+ };
+ }
+
+
+ public static void escapeStringCharacters(int length, @NotNull String str, @NotNull StringBuilder buffer) {
+ escapeStringCharacters(length, str, "\"", buffer);
+ }
+
+ @NotNull
+ public static StringBuilder escapeStringCharacters(int length,
+ @NotNull String str,
+ @Nullable String additionalChars,
+ @NotNull StringBuilder buffer) {
+ return escapeStringCharacters(length, str, additionalChars, true, buffer);
+ }
+
+ @NotNull
+ public static StringBuilder escapeStringCharacters(int length,
+ @NotNull String str,
+ @Nullable String additionalChars,
+ boolean escapeSlash,
+ @NotNull StringBuilder buffer) {
+ return escapeStringCharacters(length, str, additionalChars, escapeSlash, true, buffer);
+ }
+
+ @NotNull
+ public static StringBuilder escapeStringCharacters(int length,
+ @NotNull String str,
+ @Nullable String additionalChars,
+ boolean escapeSlash,
+ boolean escapeUnicode,
+ @NotNull StringBuilder buffer) {
+ char prev = 0;
+ for (int idx = 0; idx < length; idx++) {
+ char ch = str.charAt(idx);
+ switch (ch) {
+ case '\b':
+ buffer.append("\\b");
+ break;
+
+ case '\t':
+ buffer.append("\\t");
+ break;
+
+ case '\n':
+ buffer.append("\\n");
+ break;
+
+ case '\f':
+ buffer.append("\\f");
+ break;
+
+ case '\r':
+ buffer.append("\\r");
+ break;
+
+ default:
+ if (escapeSlash && ch == '\\') {
+ buffer.append("\\\\");
+ }
+ else if (additionalChars != null && additionalChars.indexOf(ch) > -1 && (escapeSlash || prev != '\\')) {
+ buffer.append("\\").append(ch);
+ }
+ else if (escapeUnicode && !isPrintableUnicode(ch)) {
+ CharSequence hexCode = toUpperCase(Integer.toHexString(ch));
+ buffer.append("\\u");
+ int paddingCount = 4 - hexCode.length();
+ while (paddingCount-- > 0) {
+ buffer.append(0);
+ }
+ buffer.append(hexCode);
+ }
+ else {
+ buffer.append(ch);
+ }
+ }
+ prev = ch;
+ }
+ return buffer;
+ }
+
+ @Contract(pure = true)
+ public static boolean isPrintableUnicode(char c) {
+ int t = Character.getType(c);
+ return t != Character.UNASSIGNED && t != Character.LINE_SEPARATOR && t != Character.PARAGRAPH_SEPARATOR &&
+ t != Character.CONTROL && t != Character.FORMAT && t != Character.PRIVATE_USE && t != Character.SURROGATE;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeStringCharacters(@NotNull String s) {
+ StringBuilder buffer = new StringBuilder(s.length());
+ escapeStringCharacters(s.length(), s, "\"", buffer);
+ return buffer.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeCharCharacters(@NotNull String s) {
+ StringBuilder buffer = new StringBuilder(s.length());
+ escapeStringCharacters(s.length(), s, "\'", buffer);
+ return buffer.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String unescapeStringCharacters(@NotNull String s) {
+ StringBuilder buffer = new StringBuilder(s.length());
+ unescapeStringCharacters(s.length(), s, buffer);
+ return buffer.toString();
+ }
+
+ private static boolean isQuoteAt(@NotNull String s, int ind) {
+ char ch = s.charAt(ind);
+ return ch == '\'' || ch == '\"';
+ }
+
+ @Contract(pure = true)
+ public static boolean isQuotedString(@NotNull String s) {
+ return StringUtilRt.isQuotedString(s);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String unquoteString(@NotNull String s) {
+ return StringUtilRt.unquoteString(s);
+ }
+
+ private static void unescapeStringCharacters(int length, @NotNull String s, @NotNull StringBuilder buffer) {
+ boolean escaped = false;
+ for (int idx = 0; idx < length; idx++) {
+ char ch = s.charAt(idx);
+ if (!escaped) {
+ if (ch == '\\') {
+ escaped = true;
+ }
+ else {
+ buffer.append(ch);
+ }
+ }
+ else {
+ int octalEscapeMaxLength = 2;
+ switch (ch) {
+ case 'n':
+ buffer.append('\n');
+ break;
+
+ case 'r':
+ buffer.append('\r');
+ break;
+
+ case 'b':
+ buffer.append('\b');
+ break;
+
+ case 't':
+ buffer.append('\t');
+ break;
+
+ case 'f':
+ buffer.append('\f');
+ break;
+
+ case '\'':
+ buffer.append('\'');
+ break;
+
+ case '\"':
+ buffer.append('\"');
+ break;
+
+ case '\\':
+ buffer.append('\\');
+ break;
+
+ case 'u':
+ if (idx + 4 < length) {
+ try {
+ int code = Integer.parseInt(s.substring(idx + 1, idx + 5), 16);
+ //noinspection AssignmentToForLoopParameter
+ idx += 4;
+ buffer.append((char)code);
+ }
+ catch (NumberFormatException e) {
+ buffer.append("\\u");
+ }
+ }
+ else {
+ buffer.append("\\u");
+ }
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ octalEscapeMaxLength = 3;
+ //noinspection fallthrough
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ int escapeEnd = idx + 1;
+ while (escapeEnd < length && escapeEnd < idx + octalEscapeMaxLength && isOctalDigit(s.charAt(escapeEnd))) escapeEnd++;
+ try {
+ buffer.append((char)Integer.parseInt(s.substring(idx, escapeEnd), 8));
+ }
+ catch (NumberFormatException e) {
+ throw new RuntimeException("Couldn't parse " + s.substring(idx, escapeEnd), e); // shouldn't happen
+ }
+ //noinspection AssignmentToForLoopParameter
+ idx = escapeEnd - 1;
+ break;
+
+ default:
+ buffer.append(ch);
+ break;
+ }
+ escaped = false;
+ }
+ }
+
+ if (escaped) buffer.append('\\');
+ }
+
+// @NotNull
+// @Contract(pure = true)
+// public static String pluralize(@NotNull String word) {
+// String plural = Pluralizer.PLURALIZER.plural(word);
+// if (plural != null) return plural;
+// if (word.endsWith("s")) return Pluralizer.restoreCase(word, word + "es");
+// return Pluralizer.restoreCase(word, word + "s");
+// }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String capitalizeWords(@NotNull String text,
+ boolean allWords) {
+ return capitalizeWords(text, " \t\n\r\f", allWords, false);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String capitalizeWords(@NotNull String text,
+ @NotNull String tokenizerDelim,
+ boolean allWords,
+ boolean leaveOriginalDelims) {
+ final StringTokenizer tokenizer = new StringTokenizer(text, tokenizerDelim, leaveOriginalDelims);
+ final StringBuilder out = new StringBuilder(text.length());
+ boolean toCapitalize = true;
+ while (tokenizer.hasMoreTokens()) {
+ final String word = tokenizer.nextToken();
+ if (!leaveOriginalDelims && out.length() > 0) {
+ out.append(' ');
+ }
+ out.append(toCapitalize ? capitalize(word) : word);
+ if (!allWords) {
+ toCapitalize = false;
+ }
+ }
+ return out.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String decapitalize(@NotNull String s) {
+ return Introspector.decapitalize(s);
+ }
+
+ @Contract(pure = true)
+ public static boolean isVowel(char c) {
+ return VOWELS.indexOf(c) >= 0;
+ }
+
+ /**
+ * Capitalize the first letter of the sentence.
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String capitalize(@NotNull String s) {
+ if (s.isEmpty()) return s;
+ if (s.length() == 1) return toUpperCase(s).toString();
+
+ // Optimization
+ if (Character.isUpperCase(s.charAt(0))) return s;
+ return toUpperCase(s.charAt(0)) + s.substring(1);
+ }
+
+ @Contract(value = "null -> false", pure = true)
+ public static boolean isCapitalized(@Nullable String s) {
+ return s != null && !s.isEmpty() && Character.isUpperCase(s.charAt(0));
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String capitalizeWithJavaBeanConvention(@NotNull String s) {
+ if (s.length() > 1 && Character.isUpperCase(s.charAt(1))) {
+ return s;
+ }
+ return capitalize(s);
+ }
+
+ @Contract(pure = true)
+ public static int stringHashCode(@NotNull CharSequence chars) {
+ if (chars instanceof String || chars instanceof CharSequenceWithStringHash) {
+ // we know for sure these classes have conformant (and maybe faster) hashCode()
+ return chars.hashCode();
+ }
+
+ return stringHashCode(chars, 0, chars.length());
+ }
+
+ @Contract(pure = true)
+ public static int stringHashCode(@NotNull CharSequence chars, int from, int to) {
+ int h = 0;
+ for (int off = from; off < to; off++) {
+ h = 31 * h + chars.charAt(off);
+ }
+ return h;
+ }
+
+ @Contract(pure = true)
+ public static int stringHashCode(char[] chars, int from, int to) {
+ int h = 0;
+ for (int off = from; off < to; off++) {
+ h = 31 * h + chars[off];
+ }
+ return h;
+ }
+
+ @Contract(pure = true)
+ public static int stringHashCodeInsensitive(@NotNull char[] chars, int from, int to) {
+ int h = 0;
+ for (int off = from; off < to; off++) {
+ h = 31 * h + toLowerCase(chars[off]);
+ }
+ return h;
+ }
+
+ @Contract(pure = true)
+ public static int stringHashCodeInsensitive(@NotNull CharSequence chars, int from, int to) {
+ int h = 0;
+ for (int off = from; off < to; off++) {
+ h = 31 * h + toLowerCase(chars.charAt(off));
+ }
+ return h;
+ }
+
+ @Contract(pure = true)
+ public static int stringHashCodeInsensitive(@NotNull CharSequence chars) {
+ return stringHashCodeInsensitive(chars, 0, chars.length());
+ }
+
+ @Contract(pure = true)
+ public static int stringHashCodeIgnoreWhitespaces(@NotNull char[] chars, int from, int to) {
+ int h = 0;
+ for (int off = from; off < to; off++) {
+ char c = chars[off];
+ if (!isWhiteSpace(c)) {
+ h = 31 * h + c;
+ }
+ }
+ return h;
+ }
+
+ @Contract(pure = true)
+ public static int stringHashCodeIgnoreWhitespaces(@NotNull CharSequence chars, int from, int to) {
+ int h = 0;
+ for (int off = from; off < to; off++) {
+ char c = chars.charAt(off);
+ if (!isWhiteSpace(c)) {
+ h = 31 * h + c;
+ }
+ }
+ return h;
+ }
+
+ @Contract(pure = true)
+ public static int stringHashCodeIgnoreWhitespaces(@NotNull CharSequence chars) {
+ return stringHashCodeIgnoreWhitespaces(chars, 0, chars.length());
+ }
+
+ /**
+ * Equivalent to string.startsWith(prefixes[0] + prefixes[1] + ...) but avoids creating an object for concatenation.
+ */
+ @Contract(pure = true)
+ public static boolean startsWithConcatenation(@NotNull String string, @NotNull String... prefixes) {
+ int offset = 0;
+ for (String prefix : prefixes) {
+ int prefixLen = prefix.length();
+ if (!string.regionMatches(offset, prefix, 0, prefixLen)) {
+ return false;
+ }
+ offset += prefixLen;
+ }
+ return true;
+ }
+
+ @Contract(value = "null -> null; !null -> !null", pure = true)
+ public static String trim(@Nullable String s) {
+ return s == null ? null : s.trim();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimEnd(@NotNull String s, @NotNull String suffix) {
+ return trimEnd(s, suffix, false);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimEnd(@NotNull String s, @NotNull String suffix, boolean ignoreCase) {
+ boolean endsWith = ignoreCase ? endsWithIgnoreCase(s, suffix) : s.endsWith(suffix);
+ if (endsWith) {
+ return s.substring(0, s.length() - suffix.length());
+ }
+ return s;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimEnd(@NotNull String s, char suffix) {
+ if (endsWithChar(s, suffix)) {
+ return s.substring(0, s.length() - 1);
+ }
+ return s;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimLog(@NotNull final String text, final int limit) {
+ if (limit > 5 && text.length() > limit) {
+ return text.substring(0, limit - 5) + " ...\n";
+ }
+ return text;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimLeading(@NotNull String string) {
+ return trimLeading((CharSequence)string).toString();
+ }
+ @NotNull
+ @Contract(pure = true)
+ public static CharSequence trimLeading(@NotNull CharSequence string) {
+ int index = 0;
+ while (index < string.length() && Character.isWhitespace(string.charAt(index))) index++;
+ return string.subSequence(index, string.length());
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimLeading(@NotNull String string, char symbol) {
+ int index = 0;
+ while (index < string.length() && string.charAt(index) == symbol) index++;
+ return string.substring(index);
+ }
+
+ @NotNull
+ public static StringBuilder trimLeading(@NotNull StringBuilder builder, char symbol) {
+ int index = 0;
+ while (index < builder.length() && builder.charAt(index) == symbol) index++;
+ if (index > 0) builder.delete(0, index);
+ return builder;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimTrailing(@NotNull String string) {
+ return trimTrailing((CharSequence)string).toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static CharSequence trimTrailing(@NotNull CharSequence string) {
+ int index = string.length() - 1;
+ while (index >= 0 && Character.isWhitespace(string.charAt(index))) index--;
+ return string.subSequence(0, index + 1);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimTrailing(@NotNull String string, char symbol) {
+ int index = string.length() - 1;
+ while (index >= 0 && string.charAt(index) == symbol) index--;
+ return string.substring(0, index + 1);
+ }
+
+ @NotNull
+ public static StringBuilder trimTrailing(@NotNull StringBuilder builder, char symbol) {
+ int index = builder.length() - 1;
+ while (index >= 0 && builder.charAt(index) == symbol) index--;
+ builder.setLength(index + 1);
+ return builder;
+ }
+
+ @Contract(pure = true)
+ public static boolean startsWithChar(@Nullable CharSequence s, char prefix) {
+ return s != null && s.length() != 0 && s.charAt(0) == prefix;
+ }
+
+ @Contract(pure = true)
+ public static boolean endsWithChar(@Nullable CharSequence s, char suffix) {
+ return StringUtilRt.endsWithChar(s, suffix);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimStart(@NotNull String s, @NotNull String prefix) {
+ if (s.startsWith(prefix)) {
+ return s.substring(prefix.length());
+ }
+ return s;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String trimExtensions(@NotNull String name) {
+ int index = name.indexOf('.');
+ return index < 0 ? name : name.substring(0, index);
+ }
+
+// @NotNull
+// @Contract(pure = true)
+// public static String pluralize(@NotNull String base, int count) {
+// if (count == 1) return base;
+// return pluralize(base);
+// }
+
+ public static void repeatSymbol(@NotNull Appendable buffer, char symbol, int times) {
+ assert times >= 0 : times;
+ try {
+ for (int i = 0; i < times; i++) {
+ buffer.append(symbol);
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+
+ @Contract(pure = true)
+ public static String defaultIfEmpty(@Nullable String value, String defaultValue) {
+ return isEmpty(value) ? defaultValue : value;
+ }
+
+ @Contract(value = "null -> false", pure = true)
+ public static boolean isNotEmpty(@Nullable String s) {
+ return !isEmpty(s);
+ }
+
+ @Contract(value = "null -> true", pure = true)
+ public static boolean isEmpty(@Nullable String s) {
+ return s == null || s.isEmpty();
+ }
+
+ @Contract(value = "null -> true",pure = true)
+ public static boolean isEmpty(@Nullable CharSequence cs) {
+ return StringUtilRt.isEmpty(cs);
+ }
+
+ @Contract(pure = true)
+ public static int length(@Nullable CharSequence cs) {
+ return cs == null ? 0 : cs.length();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String notNullize(@Nullable String s) {
+ return StringUtilRt.notNullize(s);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String notNullize(@Nullable String s, @NotNull String defaultValue) {
+ return StringUtilRt.notNullize(s, defaultValue);
+ }
+
+ @Nullable
+ @Contract(pure = true)
+ public static String nullize(@Nullable String s) {
+ return nullize(s, false);
+ }
+
+ @Nullable
+ @Contract(pure = true)
+ public static String nullize(@Nullable String s, boolean nullizeSpaces) {
+ boolean empty = nullizeSpaces ? isEmptyOrSpaces(s) : isEmpty(s);
+ return empty ? null : s;
+ }
+
+ @Contract(value = "null -> true",pure = true)
+ // we need to keep this method to preserve backward compatibility
+ public static boolean isEmptyOrSpaces(@Nullable String s) {
+ return isEmptyOrSpaces((CharSequence)s);
+ }
+
+ @Contract(value = "null -> true", pure = true)
+ public static boolean isEmptyOrSpaces(@Nullable CharSequence s) {
+ return StringUtilRt.isEmptyOrSpaces(s);
+ }
+
+ /**
+ * Allows to answer if given symbol is white space, tabulation or line feed.
+ *
+ * @param c symbol to check
+ * @return {@code true} if given symbol is white space, tabulation or line feed; {@code false} otherwise
+ */
+ @Contract(pure = true)
+ public static boolean isWhiteSpace(char c) {
+ return c == '\n' || c == '\t' || c == ' ';
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String getThrowableText(@NotNull Throwable aThrowable) {
+ return ExceptionUtil.getThrowableText(aThrowable);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String repeatSymbol(final char aChar, final int count) {
+ char[] buffer = new char[count];
+ Arrays.fill(buffer, aChar);
+ return StringFactory.createShared(buffer);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String repeat(@NotNull String s, int count) {
+ assert count >= 0 : count;
+ StringBuilder sb = new StringBuilder(s.length() * count);
+ for (int i = 0; i < count; i++) {
+ sb.append(s);
+ }
+ return sb.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static List split(@NotNull String s, @NotNull String separator) {
+ return split(s, separator, true);
+ }
+ @NotNull
+ @Contract(pure = true)
+ public static List split(@NotNull CharSequence s, @NotNull CharSequence separator) {
+ return split(s, separator, true, true);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static List split(@NotNull String s, @NotNull String separator, boolean excludeSeparator) {
+ return split(s, separator, excludeSeparator, true);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ @SuppressWarnings("unchecked")
+ public static List split(@NotNull String s, @NotNull String separator, boolean excludeSeparator, boolean excludeEmptyStrings) {
+ return (List)split((CharSequence)s, separator, excludeSeparator, excludeEmptyStrings);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static List split(@NotNull CharSequence s, @NotNull CharSequence separator, boolean excludeSeparator, boolean excludeEmptyStrings) {
+ if (separator.length() == 0) {
+ return Collections.singletonList(s);
+ }
+ List result = new ArrayList();
+ int pos = 0;
+ while (true) {
+ int index = indexOf(s, separator, pos);
+ if (index == -1) break;
+ final int nextPos = index + separator.length();
+ CharSequence token = s.subSequence(pos, excludeSeparator ? index : nextPos);
+ if (token.length() != 0 || !excludeEmptyStrings) {
+ result.add(token);
+ }
+ pos = nextPos;
+ }
+ if (pos < s.length() || !excludeEmptyStrings && pos == s.length()) {
+ result.add(s.subSequence(pos, s.length()));
+ }
+ return result;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static Iterable tokenize(@NotNull String s, @NotNull String separators) {
+ final com.intellij.util.text.StringTokenizer tokenizer = new com.intellij.util.text.StringTokenizer(s, separators);
+ return new Iterable() {
+ @NotNull
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ @Override
+ public boolean hasNext() {
+ return tokenizer.hasMoreTokens();
+ }
+
+ @Override
+ public String next() {
+ return tokenizer.nextToken();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static Iterable tokenize(@NotNull final StringTokenizer tokenizer) {
+ return new Iterable() {
+ @NotNull
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ @Override
+ public boolean hasNext() {
+ return tokenizer.hasMoreTokens();
+ }
+
+ @Override
+ public String next() {
+ return tokenizer.nextToken();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * @return list containing all words in {@code text}, or {@link ContainerUtil#emptyList()} if there are none.
+ * The word here means the maximum sub-string consisting entirely of characters which are {@code Character.isJavaIdentifierPart(c)}.
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static List getWordsIn(@NotNull String text) {
+ List result = null;
+ int start = -1;
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+ boolean isIdentifierPart = Character.isJavaIdentifierPart(c);
+ if (isIdentifierPart && start == -1) {
+ start = i;
+ }
+ if (isIdentifierPart && i == text.length() - 1) {
+ if (result == null) {
+ result = new SmartList();
+ }
+ result.add(text.substring(start, i + 1));
+ }
+ else if (!isIdentifierPart && start != -1) {
+ if (result == null) {
+ result = new SmartList();
+ }
+ result.add(text.substring(start, i));
+ start = -1;
+ }
+ }
+ if (result == null) {
+ return ContainerUtil.emptyList();
+ }
+ return result;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static List getWordIndicesIn(@NotNull String text) {
+ return getWordIndicesIn(text, null);
+ }
+
+ /**
+ * @param text text to get word ranges in.
+ * @param separatorsSet if not null, only these characters will be considered as separators (i.e. not a part of word).
+ * Otherwise {@link Character#isJavaIdentifierPart(char)} will be used to determine whether a symbol is part of word.
+ * @return ranges ranges of words in passed text.
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static List getWordIndicesIn(@NotNull String text, @Nullable Set separatorsSet) {
+ List result = new SmartList();
+ int start = -1;
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+ boolean isIdentifierPart = separatorsSet == null ? Character.isJavaIdentifierPart(c) : !separatorsSet.contains(c);
+ if (isIdentifierPart && start == -1) {
+ start = i;
+ }
+ if (isIdentifierPart && i == text.length() - 1) {
+ result.add(new TextRange(start, i + 1));
+ }
+ else if (!isIdentifierPart && start != -1) {
+ result.add(new TextRange(start, i));
+ start = -1;
+ }
+ }
+ return result;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String join(@NotNull final String[] strings, @NotNull final String separator) {
+ return join(strings, 0, strings.length, separator);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String join(@NotNull final String[] strings, int startIndex, int endIndex, @NotNull final String separator) {
+ final StringBuilder result = new StringBuilder();
+ for (int i = startIndex; i < endIndex; i++) {
+ if (i > startIndex) result.append(separator);
+ result.append(strings[i]);
+ }
+ return result.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String[] zip(@NotNull String[] strings1, @NotNull String[] strings2, String separator) {
+ if (strings1.length != strings2.length) throw new IllegalArgumentException();
+
+ String[] result = ArrayUtil.newStringArray(strings1.length);
+ for (int i = 0; i < result.length; i++) {
+ result[i] = strings1[i] + separator + strings2[i];
+ }
+
+ return result;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String[] surround(@NotNull String[] strings, @NotNull String prefix, @NotNull String suffix) {
+ String[] result = ArrayUtil.newStringArray(strings.length);
+ for (int i = 0; i < result.length; i++) {
+ result[i] = prefix + strings[i] + suffix;
+ }
+ return result;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String join(@NotNull T[] items, @NotNull Function super T, String> f, @NotNull String separator) {
+ return join(Arrays.asList(items), f, separator);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String join(@NotNull Collection extends T> items,
+ @NotNull Function super T, String> f,
+ @NotNull String separator) {
+ if (items.isEmpty()) return "";
+ if (items.size() == 1) return notNullize(f.fun(items.iterator().next()));
+ return join((Iterable extends T>)items, f, separator);
+ }
+
+ @Contract(pure = true)
+ public static String join(@NotNull Iterable> items, @NotNull String separator) {
+ StringBuilder result = new StringBuilder();
+ for (Object item : items) {
+ result.append(item).append(separator);
+ }
+ if (result.length() > 0) {
+ result.setLength(result.length() - separator.length());
+ }
+ return result.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String join(@NotNull Iterable extends T> items,
+ @NotNull Function super T, String> f,
+ @NotNull String separator) {
+ StringBuilder result = new StringBuilder();
+ join(items, f, separator, result);
+ return result.toString();
+ }
+
+ public static void join(@NotNull Iterable extends T> items,
+ @NotNull Function super T, String> f,
+ @NotNull String separator,
+ @NotNull StringBuilder result) {
+ boolean isFirst = true;
+ for (T item : items) {
+ String string = f.fun(item);
+ if (!isEmpty(string)) {
+ if (isFirst) {
+ isFirst = false;
+ }
+ else {
+ result.append(separator);
+ }
+ result.append(string);
+ }
+ }
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String join(@NotNull Collection strings, @NotNull String separator) {
+ if (strings.size() <= 1) {
+ return notNullize(ContainerUtil.getFirstItem(strings));
+ }
+ StringBuilder result = new StringBuilder();
+ join(strings, separator, result);
+ return result.toString();
+ }
+
+ public static void join(@NotNull Collection strings, @NotNull String separator, @NotNull StringBuilder result) {
+ boolean isFirst = true;
+ for (String string : strings) {
+ if (string != null) {
+ if (isFirst) {
+ isFirst = false;
+ }
+ else {
+ result.append(separator);
+ }
+ result.append(string);
+ }
+ }
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String join(@NotNull final int[] strings, @NotNull final String separator) {
+ final StringBuilder result = new StringBuilder();
+ for (int i = 0; i < strings.length; i++) {
+ if (i > 0) result.append(separator);
+ result.append(strings[i]);
+ }
+ return result.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String join(@NotNull final String... strings) {
+ if (strings.length == 0) return "";
+
+ final StringBuilder builder = new StringBuilder();
+ for (final String string : strings) {
+ builder.append(string);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Consider using {@link StringUtil#unquoteString(String)} instead.
+ * Note: this method has an odd behavior:
+ * Quotes are removed even if leading and trailing quotes are different or
+ * if there is only one quote (leading or trailing).
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String stripQuotesAroundValue(@NotNull String text) {
+ final int len = text.length();
+ if (len > 0) {
+ final int from = isQuoteAt(text, 0) ? 1 : 0;
+ final int to = len > 1 && isQuoteAt(text, len - 1) ? len - 1 : len;
+ if (from > 0 || to < len) {
+ return text.substring(from, to);
+ }
+ }
+ return text;
+ }
+
+ /** Formats given duration as a sum of time units (example: {@code formatDuration(123456) = "2 m 3 s 456 ms"}). */
+ @NotNull
+ @Contract(pure = true)
+ public static String formatDuration(long duration) {
+ return formatDuration(duration, " ");
+ }
+
+ private static final String[] TIME_UNITS = {"ms", "s", "m", "h", "d", "mo", "yr", "c", "ml", "ep"};
+ private static final long[] TIME_MULTIPLIERS = {1, 1000, 60, 60, 24, 30, 12, 100, 10, 10000};
+
+ /** Formats given duration as a sum of time units (example: {@code formatDuration(123456, "") = "2m 3s 456ms"}). */
+ @NotNull
+ @Contract(pure = true)
+ public static String formatDuration(long duration, @NotNull String unitSeparator) {
+ String[] units = TIME_UNITS;
+
+ StringBuilder sb = new StringBuilder();
+ long count = duration;
+ int i = 1;
+ for (; i < units.length && count > 0; i++) {
+ long multiplier = TIME_MULTIPLIERS[i];
+ if (count < multiplier) break;
+ long remainder = count % multiplier;
+ count /= multiplier;
+ if (remainder != 0 || sb.length() > 0) {
+ if (!units[i - 1].isEmpty()) {
+ sb.insert(0, units[i - 1]);
+ sb.insert(0, unitSeparator);
+ }
+ sb.insert(0, remainder).insert(0, " ");
+ }
+ else {
+ remainder = Math.round(remainder * 100 / (double)multiplier);
+ count += remainder / 100;
+ }
+ }
+ if (!units[i - 1].isEmpty()) {
+ sb.insert(0, units[i - 1]);
+ sb.insert(0, unitSeparator);
+ }
+ sb.insert(0, count);
+ return sb.toString();
+ }
+
+ @Contract(pure = true)
+ public static boolean containsAlphaCharacters(@NotNull String value) {
+ for (int i = 0; i < value.length(); i++) {
+ if (Character.isLetter(value.charAt(i))) return true;
+ }
+ return false;
+ }
+
+ @Contract(pure = true)
+ public static boolean containsAnyChar(@NotNull final String value, @NotNull final String chars) {
+ return chars.length() > value.length()
+ ? containsAnyChar(value, chars, 0, value.length())
+ : containsAnyChar(chars, value, 0, chars.length());
+ }
+
+ @Contract(pure = true)
+ public static boolean containsAnyChar(@NotNull final String value,
+ @NotNull final String chars,
+ final int start, final int end) {
+ for (int i = start; i < end; i++) {
+ if (chars.indexOf(value.charAt(i)) >= 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Contract(pure = true)
+ public static boolean containsChar(@NotNull final String value, final char ch) {
+ return value.indexOf(ch) >= 0;
+ }
+
+ /**
+ * @deprecated use #capitalize(String)
+ */
+ @Deprecated
+ @Contract(value = "null -> null; !null -> !null", pure = true)
+ public static String firstLetterToUpperCase(@Nullable final String displayString) {
+ if (displayString == null || displayString.isEmpty()) return displayString;
+ char firstChar = displayString.charAt(0);
+ char uppedFirstChar = toUpperCase(firstChar);
+
+ if (uppedFirstChar == firstChar) return displayString;
+
+ char[] buffer = displayString.toCharArray();
+ buffer[0] = uppedFirstChar;
+ return StringFactory.createShared(buffer);
+ }
+
+ /**
+ * Strip out all characters not accepted by given filter
+ *
+ * @param s e.g. "/n my string "
+ * @param filter e.g. {@link CharFilter#NOT_WHITESPACE_FILTER}
+ * @return stripped string e.g. "mystring"
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String strip(@NotNull final String s, @NotNull final CharFilter filter) {
+ final StringBuilder result = new StringBuilder(s.length());
+ for (int i = 0; i < s.length(); i++) {
+ char ch = s.charAt(i);
+ if (filter.accept(ch)) {
+ result.append(ch);
+ }
+ }
+ return result.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static List findMatches(@NotNull String s, @NotNull Pattern pattern) {
+ return findMatches(s, pattern, 1);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static List findMatches(@NotNull String s, @NotNull Pattern pattern, int groupIndex) {
+ List result = new SmartList();
+ Matcher m = pattern.matcher(s);
+ while (m.find()) {
+ String group = m.group(groupIndex);
+ if (group != null) {
+ result.add(group);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Find position of the first character accepted by given filter.
+ *
+ * @param s the string to search
+ * @param filter search filter
+ * @return position of the first character accepted or -1 if not found
+ */
+ @Contract(pure = true)
+ public static int findFirst(@NotNull final CharSequence s, @NotNull CharFilter filter) {
+ for (int i = 0; i < s.length(); i++) {
+ char ch = s.charAt(i);
+ if (filter.accept(ch)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String replaceSubstring(@NotNull String string, @NotNull TextRange range, @NotNull String replacement) {
+ return range.replace(string, replacement);
+ }
+
+ @Contract(pure = true)
+ public static boolean startsWithWhitespace(@NotNull String text) {
+ return !text.isEmpty() && Character.isWhitespace(text.charAt(0));
+ }
+
+ @Contract(pure = true)
+ public static boolean isChar(CharSequence seq, int index, char c) {
+ return index >= 0 && index < seq.length() && seq.charAt(index) == c;
+ }
+
+ @Contract(pure = true)
+ public static boolean startsWith(@NotNull CharSequence text, @NotNull CharSequence prefix) {
+ int l1 = text.length();
+ int l2 = prefix.length();
+ if (l1 < l2) return false;
+
+ for (int i = 0; i < l2; i++) {
+ if (text.charAt(i) != prefix.charAt(i)) return false;
+ }
+
+ return true;
+ }
+
+ @Contract(pure = true)
+ public static boolean startsWith(@NotNull CharSequence text, int startIndex, @NotNull CharSequence prefix) {
+ int tl = text.length();
+ if (startIndex < 0 || startIndex > tl) {
+ throw new IllegalArgumentException("Index is out of bounds: " + startIndex + ", length: " + tl);
+ }
+ int l1 = tl - startIndex;
+ int l2 = prefix.length();
+ if (l1 < l2) return false;
+
+ for (int i = 0; i < l2; i++) {
+ if (text.charAt(i + startIndex) != prefix.charAt(i)) return false;
+ }
+
+ return true;
+ }
+
+ @Contract(pure = true)
+ public static boolean endsWith(@NotNull CharSequence text, @NotNull CharSequence suffix) {
+ int l1 = text.length();
+ int l2 = suffix.length();
+ if (l1 < l2) return false;
+
+ for (int i = l1 - 1; i >= l1 - l2; i--) {
+ if (text.charAt(i) != suffix.charAt(i + l2 - l1)) return false;
+ }
+
+ return true;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String commonPrefix(@NotNull String s1, @NotNull String s2) {
+ return s1.substring(0, commonPrefixLength(s1, s2));
+ }
+
+ @Contract(pure = true)
+ public static int commonPrefixLength(@NotNull CharSequence s1, @NotNull CharSequence s2) {
+ return commonPrefixLength(s1, s2, false);
+ }
+
+ @Contract(pure = true)
+ public static int commonPrefixLength(@NotNull CharSequence s1, @NotNull CharSequence s2, boolean ignoreCase) {
+ int i;
+ int minLength = Math.min(s1.length(), s2.length());
+ for (i = 0; i < minLength; i++) {
+ if (!charsMatch(s1.charAt(i), s2.charAt(i), ignoreCase)) {
+ break;
+ }
+ }
+ return i;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String commonSuffix(@NotNull String s1, @NotNull String s2) {
+ return s1.substring(s1.length() - commonSuffixLength(s1, s2));
+ }
+
+ @Contract(pure = true)
+ public static int commonSuffixLength(@NotNull CharSequence s1, @NotNull CharSequence s2) {
+ int s1Length = s1.length();
+ int s2Length = s2.length();
+ if (s1Length == 0 || s2Length == 0) return 0;
+ int i;
+ for (i = 0; i < s1Length && i < s2Length; i++) {
+ if (s1.charAt(s1Length - i - 1) != s2.charAt(s2Length - i - 1)) {
+ break;
+ }
+ }
+ return i;
+ }
+
+ /**
+ * Allows to answer if target symbol is contained at given char sequence at {@code [start; end)} interval.
+ *
+ * @param s target char sequence to check
+ * @param start start offset to use within the given char sequence (inclusive)
+ * @param end end offset to use within the given char sequence (exclusive)
+ * @param c target symbol to check
+ * @return {@code true} if given symbol is contained at the target range of the given char sequence;
+ * {@code false} otherwise
+ */
+ @Contract(pure = true)
+ public static boolean contains(@NotNull CharSequence s, int start, int end, char c) {
+ return indexOf(s, c, start, end) >= 0;
+ }
+
+ @Contract(pure = true)
+ public static boolean containsWhitespaces(@Nullable CharSequence s) {
+ if (s == null) return false;
+
+ for (int i = 0; i < s.length(); i++) {
+ if (Character.isWhitespace(s.charAt(i))) return true;
+ }
+ return false;
+ }
+
+ @Contract(pure = true)
+ public static int indexOf(@NotNull CharSequence s, char c) {
+ return indexOf(s, c, 0, s.length());
+ }
+
+ @Contract(pure = true)
+ public static int indexOf(@NotNull CharSequence s, char c, int start) {
+ return indexOf(s, c, start, s.length());
+ }
+
+ @Contract(pure = true)
+ public static int indexOf(@NotNull CharSequence s, char c, int start, int end) {
+ end = Math.min(end, s.length());
+ for (int i = Math.max(start, 0); i < end; i++) {
+ if (s.charAt(i) == c) return i;
+ }
+ return -1;
+ }
+
+ @Contract(pure = true)
+ public static boolean contains(@NotNull CharSequence sequence, @NotNull CharSequence infix) {
+ return indexOf(sequence, infix) >= 0;
+ }
+
+ @Contract(pure = true)
+ public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix) {
+ return indexOf(sequence, infix, 0);
+ }
+
+ @Contract(pure = true)
+ public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix, int start) {
+ return indexOf(sequence, infix, start, sequence.length());
+ }
+
+ @Contract(pure = true)
+ public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix, int start, int end) {
+ for (int i = start; i <= end - infix.length(); i++) {
+ if (startsWith(sequence, i, infix)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Contract(pure = true)
+ public static int indexOf(@NotNull CharSequence s, char c, int start, int end, boolean caseSensitive) {
+ end = Math.min(end, s.length());
+ for (int i = Math.max(start, 0); i < end; i++) {
+ if (charsMatch(s.charAt(i), c, !caseSensitive)) return i;
+ }
+ return -1;
+ }
+
+ @Contract(pure = true)
+ public static int indexOf(@NotNull char[] s, char c, int start, int end, boolean caseSensitive) {
+ end = Math.min(end, s.length);
+ for (int i = Math.max(start, 0); i < end; i++) {
+ if (charsMatch(s[i], c, !caseSensitive)) return i;
+ }
+ return -1;
+ }
+
+ @Contract(pure = true)
+ public static int indexOfSubstringEnd(@NotNull String text, @NotNull String subString) {
+ int i = text.indexOf(subString);
+ if (i == -1) return -1;
+ return i + subString.length();
+ }
+
+ @Contract(pure = true)
+ public static int indexOfAny(@NotNull final String s, @NotNull final String chars) {
+ return indexOfAny(s, chars, 0, s.length());
+ }
+
+ @Contract(pure = true)
+ public static int indexOfAny(@NotNull final CharSequence s, @NotNull final String chars) {
+ return indexOfAny(s, chars, 0, s.length());
+ }
+
+ @Contract(pure = true)
+ public static int indexOfAny(@NotNull final String s, @NotNull final String chars, final int start, final int end) {
+ return indexOfAny((CharSequence)s, chars, start, end);
+ }
+
+ @Contract(pure = true)
+ public static int indexOfAny(@NotNull final CharSequence s, @NotNull final String chars, final int start, int end) {
+ end = Math.min(end, s.length());
+ for (int i = Math.max(start, 0); i < end; i++) {
+ if (containsChar(chars, s.charAt(i))) return i;
+ }
+ return -1;
+ }
+
+ @Contract(pure = true)
+ public static int lastIndexOfAny(@NotNull CharSequence s, @NotNull final String chars) {
+ for (int i = s.length() - 1; i >= 0; i--) {
+ if (containsChar(chars, s.charAt(i))) return i;
+ }
+ return -1;
+ }
+
+ @Nullable
+ @Contract(pure = true)
+ public static String substringBefore(@NotNull String text, @NotNull String subString) {
+ int i = text.indexOf(subString);
+ if (i == -1) return null;
+ return text.substring(0, i);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String substringBeforeLast(@NotNull String text, @NotNull String subString) {
+ int i = text.lastIndexOf(subString);
+ if (i == -1) return text;
+ return text.substring(0, i);
+ }
+
+ @Nullable
+ @Contract(pure = true)
+ public static String substringAfter(@NotNull String text, @NotNull String subString) {
+ int i = text.indexOf(subString);
+ if (i == -1) return null;
+ return text.substring(i + subString.length());
+ }
+
+ @Nullable
+ @Contract(pure = true)
+ public static String substringAfterLast(@NotNull String text, @NotNull String subString) {
+ int i = text.lastIndexOf(subString);
+ if (i == -1) return null;
+ return text.substring(i + subString.length());
+ }
+
+ /**
+ * Allows to retrieve index of last occurrence of the given symbols at {@code [start; end)} sub-sequence of the given text.
+ *
+ * @param s target text
+ * @param c target symbol which last occurrence we want to check
+ * @param start start offset of the target text (inclusive)
+ * @param end end offset of the target text (exclusive)
+ * @return index of the last occurrence of the given symbol at the target sub-sequence of the given text if any;
+ * {@code -1} otherwise
+ */
+ @Contract(pure = true)
+ public static int lastIndexOf(@NotNull CharSequence s, char c, int start, int end) {
+ return StringUtilRt.lastIndexOf(s, c, start, end);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String first(@NotNull String text, final int maxLength, final boolean appendEllipsis) {
+ return text.length() > maxLength ? text.substring(0, maxLength) + (appendEllipsis ? "..." : "") : text;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static CharSequence first(@NotNull CharSequence text, final int length, final boolean appendEllipsis) {
+ if (text.length() <= length) {
+ return text;
+ }
+ if (appendEllipsis) {
+ return text.subSequence(0, length) + "...";
+ }
+ return text.subSequence(0, length);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static CharSequence last(@NotNull CharSequence text, final int length, boolean prependEllipsis) {
+ if (text.length() <= length) {
+ return text;
+ }
+ if (prependEllipsis) {
+ return "..." + text.subSequence(text.length() - length, text.length());
+ }
+ return text.subSequence(text.length() - length, text.length());
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String firstLast(@NotNull String text, int length) {
+ return text.length() > length
+ ? text.subSequence(0, length / 2) + "\u2026" + text.subSequence(text.length() - length / 2 - 1, text.length())
+ : text;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeChar(@NotNull final String str, final char character) {
+ return escapeChars(str, character);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeChars(@NotNull final String str, final char... character) {
+ final StringBuilder buf = new StringBuilder(str);
+ for (char c : character) {
+ escapeChar(buf, c);
+ }
+ return buf.toString();
+ }
+
+ public static void escapeChar(@NotNull final StringBuilder buf, final char character) {
+ int idx = 0;
+ while ((idx = indexOf(buf, character, idx)) >= 0) {
+ buf.insert(idx, "\\");
+ idx += 2;
+ }
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeQuotes(@NotNull final String str) {
+ return escapeChar(str, '"');
+ }
+
+ public static void escapeQuotes(@NotNull final StringBuilder buf) {
+ escapeChar(buf, '"');
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeSlashes(@NotNull final String str) {
+ return escapeChar(str, '/');
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeBackSlashes(@NotNull final String str) {
+ return escapeChar(str, '\\');
+ }
+
+ public static void escapeSlashes(@NotNull final StringBuilder buf) {
+ escapeChar(buf, '/');
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String unescapeSlashes(@NotNull final String str) {
+ final StringBuilder buf = new StringBuilder(str.length());
+ unescapeChar(buf, str, '/');
+ return buf.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String unescapeBackSlashes(@NotNull final String str) {
+ final StringBuilder buf = new StringBuilder(str.length());
+ unescapeChar(buf, str, '\\');
+ return buf.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String unescapeChar(@NotNull final String str, char unescapeChar) {
+ final StringBuilder buf = new StringBuilder(str.length());
+ unescapeChar(buf, str, unescapeChar);
+ return buf.toString();
+ }
+
+ private static void unescapeChar(@NotNull StringBuilder buf, @NotNull String str, char unescapeChar) {
+ final int length = str.length();
+ final int last = length - 1;
+ for (int i = 0; i < length; i++) {
+ char ch = str.charAt(i);
+ if (ch == '\\' && i != last) {
+ //noinspection AssignmentToForLoopParameter
+ i++;
+ ch = str.charAt(i);
+ if (ch != unescapeChar) buf.append('\\');
+ }
+
+ buf.append(ch);
+ }
+ }
+
+ public static void quote(@NotNull final StringBuilder builder) {
+ quote(builder, '\"');
+ }
+
+ public static void quote(@NotNull final StringBuilder builder, final char quotingChar) {
+ builder.insert(0, quotingChar);
+ builder.append(quotingChar);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String wrapWithDoubleQuote(@NotNull String str) {
+ return '\"' + str + "\"";
+ }
+
+ private static final List REPLACES_REFS = Arrays.asList("<", ">", "&", "'", """);
+ private static final List REPLACES_DISP = Arrays.asList("<", ">", "&", "'", "\"");
+
+ /**
+ * @deprecated Use {@link #unescapeXmlEntities(String)} instead
+ */
+ @Contract(value = "null -> null; !null -> !null",pure = true)
+ @Deprecated
+ public static String unescapeXml(@Nullable final String text) {
+ return text == null ? null : unescapeXmlEntities(text);
+ }
+
+ /**
+ * @deprecated Use {@link #escapeXmlEntities(String)} instead
+ */
+ @Contract(value = "null -> null; !null -> !null",pure = true)
+ @Deprecated
+ public static String escapeXml(@Nullable final String text) {
+ return text == null ? null : escapeXmlEntities(text);
+ }
+
+ /**
+ * @return {@code text} with some standard XML entities replaced with corresponding characters, e.g. '{@code <}' replaced with '<'
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String unescapeXmlEntities(@NotNull String text) {
+ return replace(text, REPLACES_REFS, REPLACES_DISP);
+ }
+
+ /**
+ * @return {@code text} with some characters replaced with standard XML entities, e.g. '<' replaced with '{@code <}'
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeXmlEntities(@NotNull String text) {
+ return replace(text, REPLACES_DISP, REPLACES_REFS);
+ }
+
+ @NotNull
+ public static String removeHtmlTags(@NotNull String htmlString) {
+ return removeHtmlTags(htmlString, false);
+ }
+
+ @NotNull
+ public static String removeHtmlTags(@NotNull String htmlString, boolean isRemoveStyleTag) {
+ if (isEmpty(htmlString)) {
+ return "";
+ }
+
+ final MyHtml2Text parser = isRemoveStyleTag ? new MyHtml2Text(true) : html2TextParser;
+ try {
+ parser.parse(new StringReader(htmlString));
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ return parser.getText();
+ }
+
+ private static final List MN_QUOTED = Arrays.asList("&&", "__");
+ private static final List MN_CHARS = Arrays.asList("&", "_");
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeMnemonics(@NotNull String text) {
+ return replace(text, MN_CHARS, MN_QUOTED);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String htmlEmphasize(@NotNull String text) {
+ return "" + escapeXmlEntities(text) + "";
+ }
+
+
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeToRegexp(@NotNull String text) {
+ final StringBuilder result = new StringBuilder(text.length());
+ return escapeToRegexp(text, result).toString();
+ }
+
+ @NotNull
+ public static StringBuilder escapeToRegexp(@NotNull CharSequence text, @NotNull StringBuilder builder) {
+ for (int i = 0; i < text.length(); i++) {
+ final char c = text.charAt(i);
+ if (c == ' ' || Character.isLetter(c) || Character.isDigit(c) || c == '_') {
+ builder.append(c);
+ }
+ else if (c == '\n') {
+ builder.append("\\n");
+ }
+ else if (c == '\r') {
+ builder.append("\\r");
+ }
+ else {
+ builder.append('\\').append(c);
+ }
+ }
+
+ return builder;
+ }
+
+ @Contract(pure = true)
+ public static boolean isEscapedBackslash(@NotNull char[] chars, int startOffset, int backslashOffset) {
+ if (chars[backslashOffset] != '\\') {
+ return true;
+ }
+ boolean escaped = false;
+ for (int i = startOffset; i < backslashOffset; i++) {
+ if (chars[i] == '\\') {
+ escaped = !escaped;
+ }
+ else {
+ escaped = false;
+ }
+ }
+ return escaped;
+ }
+
+ @Contract(pure = true)
+ public static boolean isEscapedBackslash(@NotNull CharSequence text, int startOffset, int backslashOffset) {
+ if (text.charAt(backslashOffset) != '\\') {
+ return true;
+ }
+ boolean escaped = false;
+ for (int i = startOffset; i < backslashOffset; i++) {
+ if (text.charAt(i) == '\\') {
+ escaped = !escaped;
+ }
+ else {
+ escaped = false;
+ }
+ }
+ return escaped;
+ }
+
+ /**
+ * @deprecated Use {@link #replace(String, List, List)}
+ */
+ @Deprecated
+ @NotNull
+ @Contract(pure = true)
+ public static String replace(@NotNull String text, @NotNull String[] from, @NotNull String[] to) {
+ return replace(text, Arrays.asList(from), Arrays.asList(to));
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String replace(@NotNull String text, @NotNull List from, @NotNull List to) {
+ assert from.size() == to.size();
+ StringBuilder result = null;
+ replace:
+ for (int i = 0; i < text.length(); i++) {
+ for (int j = 0; j < from.size(); j += 1) {
+ String toReplace = from.get(j);
+ String replaceWith = to.get(j);
+
+ final int len = toReplace.length();
+ if (text.regionMatches(i, toReplace, 0, len)) {
+ if (result == null) {
+ result = new StringBuilder(text.length());
+ result.append(text, 0, i);
+ }
+ result.append(replaceWith);
+ //noinspection AssignmentToForLoopParameter
+ i += len - 1;
+ continue replace;
+ }
+ }
+
+ if (result != null) {
+ result.append(text.charAt(i));
+ }
+ }
+ return result == null ? text : result.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String[] filterEmptyStrings(@NotNull String[] strings) {
+ int emptyCount = 0;
+ for (String string : strings) {
+ if (string == null || string.isEmpty()) emptyCount++;
+ }
+ if (emptyCount == 0) return strings;
+
+ String[] result = ArrayUtil.newStringArray(strings.length - emptyCount);
+ int count = 0;
+ for (String string : strings) {
+ if (string == null || string.isEmpty()) continue;
+ result[count++] = string;
+ }
+
+ return result;
+ }
+
+ @Contract(pure = true)
+ public static int countNewLines(@NotNull CharSequence text) {
+ return countChars(text, '\n');
+ }
+
+ @Contract(pure = true)
+ public static int countChars(@NotNull CharSequence text, char c) {
+ return countChars(text, c, 0, false);
+ }
+
+ @Contract(pure = true)
+ public static int countChars(@NotNull CharSequence text, char c, int offset, boolean stopAtOtherChar) {
+ return countChars(text, c, offset, text.length(), stopAtOtherChar);
+ }
+
+ @Contract(pure = true)
+ public static int countChars(@NotNull CharSequence text, char c, int start, int end, boolean stopAtOtherChar) {
+ boolean forward = start <= end;
+ start = forward ? Math.max(0, start) : Math.min(text.length(), start);
+ end = forward ? Math.min(text.length(), end) : Math.max(0, end);
+ int count = 0;
+ for (int i = forward ? start : start - 1; forward == i < end; i += forward ? 1 : -1) {
+ if (text.charAt(i) == c) {
+ count++;
+ }
+ else if (stopAtOtherChar) {
+ break;
+ }
+ }
+ return count;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String capitalsOnly(@NotNull String s) {
+ StringBuilder b = new StringBuilder();
+ for (int i = 0; i < s.length(); i++) {
+ if (Character.isUpperCase(s.charAt(i))) {
+ b.append(s.charAt(i));
+ }
+ }
+
+ return b.toString();
+ }
+
+ /**
+ * @param args Strings to join.
+ * @return {@code null} if any of given Strings is {@code null}.
+ */
+ @Nullable
+ @Contract(pure = true)
+ public static String joinOrNull(@NotNull String... args) {
+ StringBuilder r = new StringBuilder();
+ for (String arg : args) {
+ if (arg == null) return null;
+ r.append(arg);
+ }
+ return r.toString();
+ }
+
+ @Nullable
+ @Contract(pure = true)
+ public static String getPropertyName(@NotNull String methodName) {
+ if (methodName.startsWith("get")) {
+ return Introspector.decapitalize(methodName.substring(3));
+ }
+ if (methodName.startsWith("is")) {
+ return Introspector.decapitalize(methodName.substring(2));
+ }
+ if (methodName.startsWith("set")) {
+ return Introspector.decapitalize(methodName.substring(3));
+ }
+ return null;
+ }
+
+ @Contract(pure = true)
+ public static boolean isJavaIdentifierStart(char c) {
+ return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || Character.isJavaIdentifierStart(c);
+ }
+
+ @Contract(pure = true)
+ public static boolean isJavaIdentifierPart(char c) {
+ return c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || Character.isJavaIdentifierPart(c);
+ }
+
+ @Contract(pure = true)
+ public static boolean isJavaIdentifier(@NotNull String text) {
+ int len = text.length();
+ if (len == 0) return false;
+
+ if (!isJavaIdentifierStart(text.charAt(0))) return false;
+
+ for (int i = 1; i < len; i++) {
+ if (!isJavaIdentifierPart(text.charAt(i))) return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Escape property name or key in property file. Unicode characters are escaped as well.
+ *
+ * @param input an input to escape
+ * @param isKey if true, the rules for key escaping are applied. The leading space is escaped in that case.
+ * @return an escaped string
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String escapeProperty(@NotNull String input, final boolean isKey) {
+ final StringBuilder escaped = new StringBuilder(input.length());
+ for (int i = 0; i < input.length(); i++) {
+ final char ch = input.charAt(i);
+ switch (ch) {
+ case ' ':
+ if (isKey && i == 0) {
+ // only the leading space has to be escaped
+ escaped.append('\\');
+ }
+ escaped.append(' ');
+ break;
+ case '\t':
+ escaped.append("\\t");
+ break;
+ case '\r':
+ escaped.append("\\r");
+ break;
+ case '\n':
+ escaped.append("\\n");
+ break;
+ case '\f':
+ escaped.append("\\f");
+ break;
+ case '\\':
+ case '#':
+ case '!':
+ case ':':
+ case '=':
+ escaped.append('\\');
+ escaped.append(ch);
+ break;
+ default:
+ if (20 < ch && ch < 0x7F) {
+ escaped.append(ch);
+ }
+ else {
+ escaped.append("\\u");
+ escaped.append(Character.forDigit((ch >> 12) & 0xF, 16));
+ escaped.append(Character.forDigit((ch >> 8) & 0xF, 16));
+ escaped.append(Character.forDigit((ch >> 4) & 0xF, 16));
+ escaped.append(Character.forDigit((ch) & 0xF, 16));
+ }
+ break;
+ }
+ }
+ return escaped.toString();
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String getQualifiedName(@Nullable String packageName, @NotNull String className) {
+ if (packageName == null || packageName.isEmpty()) {
+ return className;
+ }
+ return packageName + '.' + className;
+ }
+
+ @Contract(pure = true)
+ public static int compareVersionNumbers(@Nullable String v1, @Nullable String v2) {
+ // todo duplicates com.intellij.util.text.VersionComparatorUtil.compare
+ // todo please refactor next time you make changes here
+ if (v1 == null && v2 == null) {
+ return 0;
+ }
+ if (v1 == null) {
+ return -1;
+ }
+ if (v2 == null) {
+ return 1;
+ }
- private static class MyHtml2Text extends HTMLEditorKit.ParserCallback {
- @NotNull private final StringBuilder myBuffer = new StringBuilder();
- private final boolean myIsSkipStyleTag;
+ String[] part1 = v1.split("[._\\-]");
+ String[] part2 = v2.split("[._\\-]");
- private boolean myIsStyleTagOpened;
+ int idx = 0;
+ for (; idx < part1.length && idx < part2.length; idx++) {
+ String p1 = part1[idx];
+ String p2 = part2[idx];
- private MyHtml2Text(boolean isSkipStyleTag) {
- myIsSkipStyleTag = isSkipStyleTag;
- }
+ int cmp;
+ if (p1.matches("\\d+") && p2.matches("\\d+")) {
+ cmp = new Integer(p1).compareTo(new Integer(p2));
+ }
+ else {
+ cmp = part1[idx].compareTo(part2[idx]);
+ }
+ if (cmp != 0) return cmp;
+ }
- public void parse(@NotNull Reader in) throws IOException {
- myBuffer.setLength(0);
- new ParserDelegator().parse(in, this, Boolean.TRUE);
+ if (part1.length != part2.length) {
+ boolean left = part1.length > idx;
+ String[] parts = left ? part1 : part2;
+
+ for (; idx < parts.length; idx++) {
+ String p = parts[idx];
+ int cmp;
+ if (p.matches("\\d+")) {
+ cmp = new Integer(p).compareTo(0);
+ }
+ else {
+ cmp = 1;
+ }
+ if (cmp != 0) return left ? cmp : -cmp;
+ }
+ }
+ return 0;
+ }
+
+ @Contract(pure = true)
+ public static int getOccurrenceCount(@NotNull String text, final char c) {
+ int res = 0;
+ int i = 0;
+ while (i < text.length()) {
+ i = text.indexOf(c, i);
+ if (i >= 0) {
+ res++;
+ i++;
+ }
+ else {
+ break;
+ }
+ }
+ return res;
+ }
+
+ @Contract(pure = true)
+ public static int getOccurrenceCount(@NotNull String text, @NotNull String s) {
+ int res = 0;
+ int i = 0;
+ while (i < text.length()) {
+ i = text.indexOf(s, i);
+ if (i >= 0) {
+ res++;
+ i++;
+ }
+ else {
+ break;
+ }
+ }
+ return res;
+ }
+
+ @Contract(pure = true)
+ public static int getIgnoreCaseOccurrenceCount(@NotNull String text, @NotNull String s) {
+ int res = 0;
+ int i = 0;
+ while (i < text.length()) {
+ i = indexOfIgnoreCase(text, s, i);
+ if (i >= 0) {
+ res++;
+ i++;
+ }
+ else {
+ break;
+ }
+ }
+ return res;
}
- @Override
- public void handleText(@NotNull char[] text, int pos) {
- if (!myIsStyleTagOpened) {
- myBuffer.append(text);
- }
+ @NotNull
+ @Contract(pure = true)
+ public static String fixVariableNameDerivedFromPropertyName(@NotNull String name) {
+ if (isEmptyOrSpaces(name)) return name;
+ char c = name.charAt(0);
+ if (isVowel(c)) {
+ return "an" + Character.toUpperCase(c) + name.substring(1);
+ }
+ return "a" + Character.toUpperCase(c) + name.substring(1);
}
- @Override
- public void handleStartTag(@NotNull HTML.Tag tag, MutableAttributeSet set, int i) {
- if (myIsSkipStyleTag && "style".equals(tag.toString())) {
- myIsStyleTagOpened = true;
- }
- handleTag(tag);
- }
+ @NotNull
+ @Contract(pure = true)
+ public static String sanitizeJavaIdentifier(@NotNull String name) {
+ final StringBuilder result = new StringBuilder(name.length());
+
+ for (int i = 0; i < name.length(); i++) {
+ final char ch = name.charAt(i);
+ if (Character.isJavaIdentifierPart(ch)) {
+ if (result.length() == 0 && !Character.isJavaIdentifierStart(ch)) {
+ result.append("_");
+ }
+ result.append(ch);
+ }
+ }
- @Override
- public void handleEndTag(@NotNull HTML.Tag tag, int pos) {
- if (myIsSkipStyleTag && "style".equals(tag.toString())) {
- myIsStyleTagOpened = false;
- }
+ return result.toString();
}
- @Override
- public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet set, int i) {
- handleTag(tag);
- }
+ public static void assertValidSeparators(@NotNull CharSequence s) {
+ char[] chars = CharArrayUtil.fromSequenceWithoutCopying(s);
+ int slashRIndex = -1;
- private void handleTag(@NotNull HTML.Tag tag) {
- if (tag.breaksFlow() && myBuffer.length() > 0) {
- myBuffer.append(SystemProperties.getLineSeparator());
- }
+ if (chars != null) {
+ for (int i = 0, len = s.length(); i < len; ++i) {
+ if (chars[i] == '\r') {
+ slashRIndex = i;
+ break;
+ }
+ }
+ }
+ else {
+ for (int i = 0, len = s.length(); i < len; i++) {
+ if (s.charAt(i) == '\r') {
+ slashRIndex = i;
+ break;
+ }
+ }
+ }
+
+ if (slashRIndex != -1) {
+ String context =
+ String.valueOf(last(s.subSequence(0, slashRIndex), 10, true)) + first(s.subSequence(slashRIndex, s.length()), 10, true);
+ context = escapeStringCharacters(context);
+ throw new AssertionError("Wrong line separators: '" + context + "' at offset " + slashRIndex);
+ }
}
@NotNull
- public String getText() {
- return myBuffer.toString();
+ @Contract(pure = true)
+ public static String tail(@NotNull String s, final int idx) {
+ return idx >= s.length() ? "" : s.substring(idx);
}
- }
- private static final MyHtml2Text html2TextParser = new MyHtml2Text(false);
+ /**
+ * Splits string by lines.
+ *
+ * @param string String to split
+ * @return array of strings
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String[] splitByLines(@NotNull String string) {
+ return splitByLines(string, true);
+ }
+
+ /**
+ * Splits string by lines. If several line separators are in a row corresponding empty lines
+ * are also added to result if {@code excludeEmptyStrings} is {@code false}.
+ *
+ * @param string String to split
+ * @return array of strings
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String[] splitByLines(@NotNull String string, boolean excludeEmptyStrings) {
+ return (excludeEmptyStrings ? EOL_SPLIT_PATTERN : EOL_SPLIT_PATTERN_WITH_EMPTY).split(string);
+ }
- public static final NotNullFunction QUOTER = new NotNullFunction() {
- @Override
@NotNull
- public String fun(String s) {
- return "\"" + s + "\"";
+ @Contract(pure = true)
+ public static String[] splitByLinesDontTrim(@NotNull String string) {
+ return EOL_SPLIT_DONT_TRIM_PATTERN.split(string);
+ }
+
+ /**
+ * Splits string by lines, keeping all line separators at the line ends and in the empty lines.
+ *
E.g. splitting text
+ *
+ * foo\r\n
+ * \n
+ * bar\n
+ * \r\n
+ * baz\r
+ * \r
+ *
+ * will return the following array: foo\r\n, \n, bar\n, \r\n, baz\r, \r
+ *
+ */
+ @NotNull
+ @Contract(pure = true)
+ public static String[] splitByLinesKeepSeparators(@NotNull String string) {
+ return EOL_SPLIT_KEEP_SEPARATORS.split(string);
}
- };
- public static final NotNullFunction SINGLE_QUOTER = new NotNullFunction() {
- @Override
@NotNull
- public String fun(String s) {
- return "'" + s + "'";
+ @Contract(pure = true)
+ public static List> getWordsWithOffset(@NotNull String s) {
+ List> res = ContainerUtil.newArrayList();
+ s += " ";
+ StringBuilder name = new StringBuilder();
+ int startInd = -1;
+ for (int i = 0; i < s.length(); i++) {
+ if (Character.isWhitespace(s.charAt(i))) {
+ if (name.length() > 0) {
+ res.add(Pair.create(name.toString(), startInd));
+ name.setLength(0);
+ startInd = -1;
+ }
+ }
+ else {
+ if (startInd == -1) {
+ startInd = i;
+ }
+ name.append(s.charAt(i));
+ }
+ }
+ return res;
+ }
+
+ @Contract(pure = true)
+ public static int naturalCompare(@Nullable String string1, @Nullable String string2) {
+ return NaturalComparator.INSTANCE.compare(string1, string2);
}
- };
- @NotNull
- @Contract(pure = true)
- public static List getWordsInStringLongestFirst(@NotNull String find) {
- List words = getWordsIn(find);
- // hope long words are rare
- Collections.sort(words, new Comparator() {
- @Override
- public int compare(@NotNull final String o1, @NotNull final String o2) {
- return o2.length() - o1.length();
- }
- });
- return words;
- }
+ @Contract(pure = true)
+ public static boolean isDecimalDigit(char c) {
+ return c >= '0' && c <= '9';
+ }
- @NotNull
- @Contract(pure = true)
- public static String escapePattern(@NotNull final String text) {
- return replace(replace(text, "'", "''"), "{", "'{'");
- }
+ @Contract("null -> false")
+ public static boolean isNotNegativeNumber(@Nullable CharSequence s) {
+ if (s == null) {
+ return false;
+ }
+ for (int i = 0; i < s.length(); i++) {
+ if (!isDecimalDigit(s.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
- @NotNull
- @Contract(pure = true)
- public static Function createToStringFunction(@SuppressWarnings("unused") @NotNull Class cls) {
- return new Function() {
- @Override
- public String fun(@NotNull T o) {
- return o.toString();
- }
- };
- }
+ @Contract(pure = true)
+ public static int compare(@Nullable String s1, @Nullable String s2, boolean ignoreCase) {
+ //noinspection StringEquality
+ if (s1 == s2) return 0;
+ if (s1 == null) return -1;
+ if (s2 == null) return 1;
+ return ignoreCase ? s1.compareToIgnoreCase(s2) : s1.compareTo(s2);
+ }
- @NotNull
- public static final Function TRIMMER = new Function() {
- @Nullable
- @Override
- public String fun(@Nullable String s) {
- return trim(s);
- }
- };
-
- // Unlike String.replace(CharSequence,CharSequence) does not allocate intermediate objects on non-match
- // TODO revise when JDK9 arrives - its String.replace(CharSequence, CharSequence) is more optimized
- @NotNull
- @Contract(pure = true)
- public static String replace(@NotNull String text, @NotNull String oldS, @NotNull String newS) {
- return replace(text, oldS, newS, false);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String replaceIgnoreCase(@NotNull String text, @NotNull String oldS, @NotNull String newS) {
- return replace(text, oldS, newS, true);
- }
-
- /**
- * @deprecated Use {@link String#replace(char,char)} instead
- */
- @NotNull
- @Contract(pure = true)
- @Deprecated
- public static String replaceChar(@NotNull String buffer, char oldChar, char newChar) {
- return buffer.replace(oldChar, newChar);
- }
-
- @Contract(pure = true)
- public static String replace(@NotNull final String text, @NotNull final String oldS, @NotNull final String newS, final boolean ignoreCase) {
- if (text.length() < oldS.length()) return text;
-
- StringBuilder newText = null;
- int i = 0;
-
- while (i < text.length()) {
- final int index = ignoreCase? indexOfIgnoreCase(text, oldS, i) : text.indexOf(oldS, i);
- if (index < 0) {
- if (i == 0) {
- return text;
- }
-
- newText.append(text, i, text.length());
- break;
- }
- else {
- if (newText == null) {
- if (text.length() == oldS.length()) {
- return newS;
- }
- newText = new StringBuilder(text.length() - i);
- }
-
- newText.append(text, i, index);
- newText.append(newS);
- i = index + oldS.length();
- }
- }
- return newText != null ? newText.toString() : "";
- }
-
- @Contract(pure = true)
- public static int indexOfIgnoreCase(@NotNull String where, @NotNull String what, int fromIndex) {
- return indexOfIgnoreCase((CharSequence)where, what, fromIndex);
- }
-
- /**
- * Implementation copied from {@link String#indexOf(String, int)} except character comparisons made case insensitive
- */
- @Contract(pure = true)
- public static int indexOfIgnoreCase(@NotNull CharSequence where, @NotNull CharSequence what, int fromIndex) {
- int targetCount = what.length();
- int sourceCount = where.length();
-
- if (fromIndex >= sourceCount) {
- return targetCount == 0 ? sourceCount : -1;
- }
-
- if (fromIndex < 0) {
- fromIndex = 0;
- }
-
- if (targetCount == 0) {
- return fromIndex;
- }
-
- char first = what.charAt(0);
- int max = sourceCount - targetCount;
-
- for (int i = fromIndex; i <= max; i++) {
- /* Look for first character. */
- if (!charsEqualIgnoreCase(where.charAt(i), first)) {
- //noinspection StatementWithEmptyBody,AssignmentToForLoopParameter
- while (++i <= max && !charsEqualIgnoreCase(where.charAt(i), first)) ;
- }
-
- /* Found first character, now look at the rest of v2 */
- if (i <= max) {
- int j = i + 1;
- int end = j + targetCount - 1;
- //noinspection StatementWithEmptyBody
- for (int k = 1; j < end && charsEqualIgnoreCase(where.charAt(j), what.charAt(k)); j++, k++) ;
-
- if (j == end) {
- /* Found whole string. */
- return i;
- }
- }
- }
-
- return -1;
- }
-
- @Contract(pure = true)
- public static int indexOfIgnoreCase(@NotNull String where, char what, int fromIndex) {
- int sourceCount = where.length();
- for (int i = Math.max(fromIndex, 0); i < sourceCount; i++) {
- if (charsEqualIgnoreCase(where.charAt(i), what)) {
- return i;
- }
+ @Contract(pure = true)
+ public static int comparePairs(@Nullable String s1, @Nullable String t1, @Nullable String s2, @Nullable String t2, boolean ignoreCase) {
+ final int compare = compare(s1, s2, ignoreCase);
+ return compare != 0 ? compare : compare(t1, t2, ignoreCase);
+ }
+
+ @Contract(pure = true)
+ public static int hashCode(@NotNull CharSequence s) {
+ return stringHashCode(s);
}
- return -1;
- }
+ @Contract(pure = true)
+ public static boolean equals(@Nullable CharSequence s1, @Nullable CharSequence s2) {
+ if (s1 == null ^ s2 == null) {
+ return false;
+ }
- @Contract(pure = true)
- public static int lastIndexOfIgnoreCase(@NotNull String where, char what, int fromIndex) {
- for (int i = Math.min(fromIndex, where.length() - 1); i >= 0; i--) {
- if (charsEqualIgnoreCase(where.charAt(i), what)) {
- return i;
- }
- }
-
- return -1;
- }
-
- @Contract(pure = true)
- public static boolean containsIgnoreCase(@NotNull String where, @NotNull String what) {
- return indexOfIgnoreCase(where, what, 0) >= 0;
- }
-
- @Contract(pure = true)
- public static boolean endsWithIgnoreCase(@NotNull String str, @NotNull String suffix) {
- return StringUtilRt.endsWithIgnoreCase(str, suffix);
- }
-
- @Contract(pure = true)
- public static boolean startsWithIgnoreCase(@NotNull String str, @NotNull String prefix) {
- return StringUtilRt.startsWithIgnoreCase(str, prefix);
- }
-
- @Contract(pure = true)
- @NotNull
- public static String stripHtml(@NotNull String html, boolean convertBreaks) {
- if (convertBreaks) {
- html = html.replaceAll("
", "\n\n");
- }
-
- return html.replaceAll("<(.|\n)*?>", "");
- }
-
- @Contract(value = "null -> null; !null -> !null", pure = true)
- public static String toLowerCase(@Nullable final String str) {
- return str == null ? null : str.toLowerCase();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String getPackageName(@NotNull String fqName) {
- return getPackageName(fqName, '.');
- }
-
- /**
- * Given a fqName returns the package name for the type or the containing type.
- *
- *
- * - {@code java.lang.String} -> {@code java.lang}
- * - {@code java.util.Map.Entry} -> {@code java.util.Map}
- *
- *
- * @param fqName a fully qualified type name. Not supposed to contain any type arguments
- * @param separator the separator to use. Typically '.'
- * @return the package name of the type or the declarator of the type. The empty string if the given fqName is unqualified
- */
- @NotNull
- @Contract(pure = true)
- public static String getPackageName(@NotNull String fqName, char separator) {
- int lastPointIdx = fqName.lastIndexOf(separator);
- if (lastPointIdx >= 0) {
- return fqName.substring(0, lastPointIdx);
- }
- return "";
- }
-
- @Contract(pure = true)
- public static int getLineBreakCount(@NotNull CharSequence text) {
- int count = 0;
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- if (c == '\n') {
- count++;
- }
- else if (c == '\r') {
- if (i + 1 < text.length() && text.charAt(i + 1) == '\n') {
- //noinspection AssignmentToForLoopParameter
- i++;
- }
- count++;
- }
- }
- return count;
- }
-
- @Contract(pure = true)
- public static boolean containsLineBreak(@NotNull CharSequence text) {
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- if (isLineBreak(c)) return true;
- }
- return false;
- }
-
- @Contract(pure = true)
- public static boolean isLineBreak(char c) {
- return c == '\n' || c == '\r';
- }
-
- @NotNull
- @Contract(pure = true)
- public static String escapeLineBreak(@NotNull String text) {
- StringBuilder buffer = new StringBuilder(text.length());
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- switch (c) {
- case '\n':
- buffer.append("\\n");
- break;
- case '\r':
- buffer.append("\\r");
- break;
- default:
- buffer.append(c);
- }
- }
- return buffer.toString();
- }
-
- @Contract(pure = true)
- public static boolean endsWithLineBreak(@NotNull CharSequence text) {
- int len = text.length();
- return len > 0 && isLineBreak(text.charAt(len - 1));
- }
-
- @Contract(pure = true)
- public static int lineColToOffset(@NotNull CharSequence text, int line, int col) {
- int curLine = 0;
- int offset = 0;
- while (line != curLine) {
- if (offset == text.length()) return -1;
- char c = text.charAt(offset);
- if (c == '\n') {
- curLine++;
- }
- else if (c == '\r') {
- curLine++;
- if (offset < text.length() - 1 && text.charAt(offset + 1) == '\n') {
- offset++;
- }
- }
- offset++;
- }
- return offset + col;
- }
-
- @Contract(pure = true)
- public static int offsetToLineNumber(@NotNull CharSequence text, int offset) {
- LineColumn lineColumn = offsetToLineColumn(text, offset);
- return lineColumn != null ? lineColumn.line : -1;
- }
-
- @Contract(pure = true)
- public static LineColumn offsetToLineColumn(@NotNull CharSequence text, int offset) {
- int curLine = 0;
- int curLineStart = 0;
- int curOffset = 0;
- while (curOffset < offset) {
- if (curOffset == text.length()) return null;
- char c = text.charAt(curOffset);
- if (c == '\n') {
- curLine++;
- curLineStart = curOffset + 1;
- }
- else if (c == '\r') {
- curLine++;
- if (curOffset < text.length() - 1 && text.charAt(curOffset + 1) == '\n') {
- curOffset++;
- }
- curLineStart = curOffset + 1;
- }
- curOffset++;
- }
-
- return LineColumn.of(curLine, offset - curLineStart);
- }
-
- /**
- * Classic dynamic programming algorithm for string differences.
- */
- @Contract(pure = true)
- public static int difference(@NotNull String s1, @NotNull String s2) {
- int[][] a = new int[s1.length()][s2.length()];
-
- for (int i = 0; i < s1.length(); i++) {
- a[i][0] = i;
- }
-
- for (int j = 0; j < s2.length(); j++) {
- a[0][j] = j;
- }
-
- for (int i = 1; i < s1.length(); i++) {
- for (int j = 1; j < s2.length(); j++) {
-
- a[i][j] = Math.min(Math.min(a[i - 1][j - 1] + (s1.charAt(i) == s2.charAt(j) ? 0 : 1), a[i - 1][j] + 1), a[i][j - 1] + 1);
- }
- }
-
- return a[s1.length() - 1][s2.length() - 1];
- }
-
- @NotNull
- @Contract(pure = true)
- public static String wordsToBeginFromUpperCase(@NotNull String s) {
- return fixCapitalization(s, ourPrepositions, true);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String wordsToBeginFromLowerCase(@NotNull String s) {
- return fixCapitalization(s, ourPrepositions, false);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String toTitleCase(@NotNull String s) {
- return fixCapitalization(s, ArrayUtil.EMPTY_STRING_ARRAY, true);
- }
-
- @NotNull
- private static String fixCapitalization(@NotNull String s, @NotNull String[] prepositions, boolean title) {
- StringBuilder buffer = null;
- for (int i = 0; i < s.length(); i++) {
- char prevChar = i == 0 ? ' ' : s.charAt(i - 1);
- char currChar = s.charAt(i);
- if (!Character.isLetterOrDigit(prevChar) && prevChar != '\'') {
- if (Character.isLetterOrDigit(currChar)) {
- if (title || Character.isUpperCase(currChar)) {
- int j = i;
- for (; j < s.length(); j++) {
- if (!Character.isLetterOrDigit(s.charAt(j))) {
- break;
- }
- }
- if (!title && j > i + 1 && !Character.isLowerCase(s.charAt(i + 1))) {
- // filter out abbreviations like I18n, SQL and CSS
- continue;
- }
- if (!isPreposition(s, i, j - 1, prepositions)) {
- if (buffer == null) {
- buffer = new StringBuilder(s);
- }
- buffer.setCharAt(i, title ? toUpperCase(currChar) : toLowerCase(currChar));
- }
- }
- }
- }
- }
- return buffer == null ? s : buffer.toString();
- }
-
- private static final String[] ourPrepositions = {
- "a", "an", "and", "as", "at", "but", "by", "down", "for", "from", "if", "in", "into", "not", "of", "on", "onto", "or", "out", "over",
- "per", "nor", "the", "to", "up", "upon", "via", "with"
- };
-
- @Contract(pure = true)
- public static boolean isPreposition(@NotNull String s, int firstChar, int lastChar) {
- return isPreposition(s, firstChar, lastChar, ourPrepositions);
- }
-
- @Contract(pure = true)
- public static boolean isPreposition(@NotNull String s, int firstChar, int lastChar, @NotNull String[] prepositions) {
- for (String preposition : prepositions) {
- boolean found = false;
- if (lastChar - firstChar + 1 == preposition.length()) {
- found = true;
- for (int j = 0; j < preposition.length(); j++) {
- if (toLowerCase(s.charAt(firstChar + j)) != preposition.charAt(j)) {
- found = false;
- }
- }
- }
- if (found) {
+ if (s1 == null) {
+ return true;
+ }
+
+ if (s1.length() != s2.length()) {
+ return false;
+ }
+ for (int i = 0; i < s1.length(); i++) {
+ if (s1.charAt(i) != s2.charAt(i)) {
+ return false;
+ }
+ }
return true;
- }
- }
- return false;
- }
-
- @NotNull
- @Contract(pure = true)
- public static NotNullFunction escaper(final boolean escapeSlash, @Nullable final String additionalChars) {
- return new NotNullFunction() {
- @NotNull
- @Override
- public String fun(@NotNull String dom) {
- final StringBuilder builder = new StringBuilder(dom.length());
- escapeStringCharacters(dom.length(), dom, additionalChars, escapeSlash, builder);
- return builder.toString();
- }
- };
- }
-
-
- public static void escapeStringCharacters(int length, @NotNull String str, @NotNull StringBuilder buffer) {
- escapeStringCharacters(length, str, "\"", buffer);
- }
-
- @NotNull
- public static StringBuilder escapeStringCharacters(int length,
- @NotNull String str,
- @Nullable String additionalChars,
- @NotNull StringBuilder buffer) {
- return escapeStringCharacters(length, str, additionalChars, true, buffer);
- }
-
- @NotNull
- public static StringBuilder escapeStringCharacters(int length,
- @NotNull String str,
- @Nullable String additionalChars,
- boolean escapeSlash,
- @NotNull StringBuilder buffer) {
- return escapeStringCharacters(length, str, additionalChars, escapeSlash, true, buffer);
- }
-
- @NotNull
- public static StringBuilder escapeStringCharacters(int length,
- @NotNull String str,
- @Nullable String additionalChars,
- boolean escapeSlash,
- boolean escapeUnicode,
- @NotNull StringBuilder buffer) {
- char prev = 0;
- for (int idx = 0; idx < length; idx++) {
- char ch = str.charAt(idx);
- switch (ch) {
- case '\b':
- buffer.append("\\b");
- break;
-
- case '\t':
- buffer.append("\\t");
- break;
-
- case '\n':
- buffer.append("\\n");
- break;
-
- case '\f':
- buffer.append("\\f");
- break;
-
- case '\r':
- buffer.append("\\r");
- break;
-
- default:
- if (escapeSlash && ch == '\\') {
- buffer.append("\\\\");
- }
- else if (additionalChars != null && additionalChars.indexOf(ch) > -1 && (escapeSlash || prev != '\\')) {
- buffer.append("\\").append(ch);
- }
- else if (escapeUnicode && !isPrintableUnicode(ch)) {
- CharSequence hexCode = toUpperCase(Integer.toHexString(ch));
- buffer.append("\\u");
- int paddingCount = 4 - hexCode.length();
- while (paddingCount-- > 0) {
- buffer.append(0);
- }
- buffer.append(hexCode);
- }
- else {
- buffer.append(ch);
- }
- }
- prev = ch;
- }
- return buffer;
- }
-
- @Contract(pure = true)
- public static boolean isPrintableUnicode(char c) {
- int t = Character.getType(c);
- return t != Character.UNASSIGNED && t != Character.LINE_SEPARATOR && t != Character.PARAGRAPH_SEPARATOR &&
- t != Character.CONTROL && t != Character.FORMAT && t != Character.PRIVATE_USE && t != Character.SURROGATE;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String escapeStringCharacters(@NotNull String s) {
- StringBuilder buffer = new StringBuilder(s.length());
- escapeStringCharacters(s.length(), s, "\"", buffer);
- return buffer.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String escapeCharCharacters(@NotNull String s) {
- StringBuilder buffer = new StringBuilder(s.length());
- escapeStringCharacters(s.length(), s, "\'", buffer);
- return buffer.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String unescapeStringCharacters(@NotNull String s) {
- StringBuilder buffer = new StringBuilder(s.length());
- unescapeStringCharacters(s.length(), s, buffer);
- return buffer.toString();
- }
-
- private static boolean isQuoteAt(@NotNull String s, int ind) {
- char ch = s.charAt(ind);
- return ch == '\'' || ch == '\"';
- }
-
- @Contract(pure = true)
- public static boolean isQuotedString(@NotNull String s) {
- return StringUtilRt.isQuotedString(s);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String unquoteString(@NotNull String s) {
- return StringUtilRt.unquoteString(s);
- }
-
- private static void unescapeStringCharacters(int length, @NotNull String s, @NotNull StringBuilder buffer) {
- boolean escaped = false;
- for (int idx = 0; idx < length; idx++) {
- char ch = s.charAt(idx);
- if (!escaped) {
- if (ch == '\\') {
- escaped = true;
+ }
+
+ @Contract(pure = true)
+ public static boolean equalsIgnoreCase(@Nullable CharSequence s1, @Nullable CharSequence s2) {
+ if (s1 == null ^ s2 == null) {
+ return false;
}
- else {
- buffer.append(ch);
- }
- }
- else {
- int octalEscapeMaxLength = 2;
- switch (ch) {
- case 'n':
- buffer.append('\n');
- break;
-
- case 'r':
- buffer.append('\r');
- break;
-
- case 'b':
- buffer.append('\b');
- break;
-
- case 't':
- buffer.append('\t');
- break;
-
- case 'f':
- buffer.append('\f');
- break;
-
- case '\'':
- buffer.append('\'');
- break;
-
- case '\"':
- buffer.append('\"');
- break;
-
- case '\\':
- buffer.append('\\');
- break;
-
- case 'u':
- if (idx + 4 < length) {
- try {
- int code = Integer.parseInt(s.substring(idx + 1, idx + 5), 16);
- //noinspection AssignmentToForLoopParameter
- idx += 4;
- buffer.append((char)code);
- }
- catch (NumberFormatException e) {
- buffer.append("\\u");
- }
+
+ if (s1 == null) {
+ return true;
+ }
+
+ if (s1.length() != s2.length()) {
+ return false;
+ }
+ for (int i = 0; i < s1.length(); i++) {
+ if (!charsEqualIgnoreCase(s1.charAt(i), s2.charAt(i))) {
+ return false;
}
- else {
- buffer.append("\\u");
+ }
+ return true;
+ }
+
+ @Contract(pure = true)
+ public static boolean equalsIgnoreWhitespaces(@Nullable CharSequence s1, @Nullable CharSequence s2) {
+ if (s1 == null ^ s2 == null) {
+ return false;
+ }
+
+ if (s1 == null) {
+ return true;
+ }
+
+ int len1 = s1.length();
+ int len2 = s2.length();
+
+ int index1 = 0;
+ int index2 = 0;
+ while (index1 < len1 && index2 < len2) {
+ if (s1.charAt(index1) == s2.charAt(index2)) {
+ index1++;
+ index2++;
+ continue;
}
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- octalEscapeMaxLength = 3;
- //noinspection fallthrough
- case '4':
- case '5':
- case '6':
- case '7':
- int escapeEnd = idx + 1;
- while (escapeEnd < length && escapeEnd < idx + octalEscapeMaxLength && isOctalDigit(s.charAt(escapeEnd))) escapeEnd++;
- try {
- buffer.append((char)Integer.parseInt(s.substring(idx, escapeEnd), 8));
+ boolean skipped = false;
+ while (index1 != len1 && isWhiteSpace(s1.charAt(index1))) {
+ skipped = true;
+ index1++;
}
- catch (NumberFormatException e) {
- throw new RuntimeException("Couldn't parse " + s.substring(idx, escapeEnd), e); // shouldn't happen
+ while (index2 != len2 && isWhiteSpace(s2.charAt(index2))) {
+ skipped = true;
+ index2++;
}
- //noinspection AssignmentToForLoopParameter
- idx = escapeEnd - 1;
- break;
- default:
- buffer.append(ch);
- break;
+ if (!skipped) return false;
}
- escaped = false;
- }
- }
- if (escaped) buffer.append('\\');
- }
+ for (; index1 != len1; index1++) {
+ if (!isWhiteSpace(s1.charAt(index1))) return false;
+ }
+ for (; index2 != len2; index2++) {
+ if (!isWhiteSpace(s2.charAt(index2))) return false;
+ }
-// @NotNull
-// @Contract(pure = true)
-// public static String pluralize(@NotNull String word) {
-// String plural = Pluralizer.PLURALIZER.plural(word);
-// if (plural != null) return plural;
-// if (word.endsWith("s")) return Pluralizer.restoreCase(word, word + "es");
-// return Pluralizer.restoreCase(word, word + "s");
-// }
+ return true;
+ }
- @NotNull
- @Contract(pure = true)
- public static String capitalizeWords(@NotNull String text,
- boolean allWords) {
- return capitalizeWords(text, " \t\n\r\f", allWords, false);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String capitalizeWords(@NotNull String text,
- @NotNull String tokenizerDelim,
- boolean allWords,
- boolean leaveOriginalDelims) {
- final StringTokenizer tokenizer = new StringTokenizer(text, tokenizerDelim, leaveOriginalDelims);
- final StringBuilder out = new StringBuilder(text.length());
- boolean toCapitalize = true;
- while (tokenizer.hasMoreTokens()) {
- final String word = tokenizer.nextToken();
- if (!leaveOriginalDelims && out.length() > 0) {
- out.append(' ');
- }
- out.append(toCapitalize ? capitalize(word) : word);
- if (!allWords) {
- toCapitalize = false;
- }
- }
- return out.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String decapitalize(@NotNull String s) {
- return Introspector.decapitalize(s);
- }
-
- @Contract(pure = true)
- public static boolean isVowel(char c) {
- return VOWELS.indexOf(c) >= 0;
- }
-
- /**
- * Capitalize the first letter of the sentence.
- */
- @NotNull
- @Contract(pure = true)
- public static String capitalize(@NotNull String s) {
- if (s.isEmpty()) return s;
- if (s.length() == 1) return toUpperCase(s).toString();
-
- // Optimization
- if (Character.isUpperCase(s.charAt(0))) return s;
- return toUpperCase(s.charAt(0)) + s.substring(1);
- }
-
- @Contract(value = "null -> false", pure = true)
- public static boolean isCapitalized(@Nullable String s) {
- return s != null && !s.isEmpty() && Character.isUpperCase(s.charAt(0));
- }
-
- @NotNull
- @Contract(pure = true)
- public static String capitalizeWithJavaBeanConvention(@NotNull String s) {
- if (s.length() > 1 && Character.isUpperCase(s.charAt(1))) {
- return s;
- }
- return capitalize(s);
- }
-
- @Contract(pure = true)
- public static int stringHashCode(@NotNull CharSequence chars) {
- if (chars instanceof String || chars instanceof CharSequenceWithStringHash) {
- // we know for sure these classes have conformant (and maybe faster) hashCode()
- return chars.hashCode();
- }
-
- return stringHashCode(chars, 0, chars.length());
- }
-
- @Contract(pure = true)
- public static int stringHashCode(@NotNull CharSequence chars, int from, int to) {
- int h = 0;
- for (int off = from; off < to; off++) {
- h = 31 * h + chars.charAt(off);
- }
- return h;
- }
-
- @Contract(pure = true)
- public static int stringHashCode(char[] chars, int from, int to) {
- int h = 0;
- for (int off = from; off < to; off++) {
- h = 31 * h + chars[off];
- }
- return h;
- }
-
- @Contract(pure = true)
- public static int stringHashCodeInsensitive(@NotNull char[] chars, int from, int to) {
- int h = 0;
- for (int off = from; off < to; off++) {
- h = 31 * h + toLowerCase(chars[off]);
- }
- return h;
- }
-
- @Contract(pure = true)
- public static int stringHashCodeInsensitive(@NotNull CharSequence chars, int from, int to) {
- int h = 0;
- for (int off = from; off < to; off++) {
- h = 31 * h + toLowerCase(chars.charAt(off));
- }
- return h;
- }
-
- @Contract(pure = true)
- public static int stringHashCodeInsensitive(@NotNull CharSequence chars) {
- return stringHashCodeInsensitive(chars, 0, chars.length());
- }
-
- @Contract(pure = true)
- public static int stringHashCodeIgnoreWhitespaces(@NotNull char[] chars, int from, int to) {
- int h = 0;
- for (int off = from; off < to; off++) {
- char c = chars[off];
- if (!isWhiteSpace(c)) {
- h = 31 * h + c;
- }
- }
- return h;
- }
-
- @Contract(pure = true)
- public static int stringHashCodeIgnoreWhitespaces(@NotNull CharSequence chars, int from, int to) {
- int h = 0;
- for (int off = from; off < to; off++) {
- char c = chars.charAt(off);
- if (!isWhiteSpace(c)) {
- h = 31 * h + c;
- }
- }
- return h;
- }
-
- @Contract(pure = true)
- public static int stringHashCodeIgnoreWhitespaces(@NotNull CharSequence chars) {
- return stringHashCodeIgnoreWhitespaces(chars, 0, chars.length());
- }
-
- /**
- * Equivalent to string.startsWith(prefixes[0] + prefixes[1] + ...) but avoids creating an object for concatenation.
- */
- @Contract(pure = true)
- public static boolean startsWithConcatenation(@NotNull String string, @NotNull String... prefixes) {
- int offset = 0;
- for (String prefix : prefixes) {
- int prefixLen = prefix.length();
- if (!string.regionMatches(offset, prefix, 0, prefixLen)) {
- return false;
- }
- offset += prefixLen;
- }
- return true;
- }
-
- @Contract(value = "null -> null; !null -> !null", pure = true)
- public static String trim(@Nullable String s) {
- return s == null ? null : s.trim();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimEnd(@NotNull String s, @NotNull String suffix) {
- return trimEnd(s, suffix, false);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimEnd(@NotNull String s, @NotNull String suffix, boolean ignoreCase) {
- boolean endsWith = ignoreCase ? endsWithIgnoreCase(s, suffix) : s.endsWith(suffix);
- if (endsWith) {
- return s.substring(0, s.length() - suffix.length());
- }
- return s;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimEnd(@NotNull String s, char suffix) {
- if (endsWithChar(s, suffix)) {
- return s.substring(0, s.length() - 1);
- }
- return s;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimLog(@NotNull final String text, final int limit) {
- if (limit > 5 && text.length() > limit) {
- return text.substring(0, limit - 5) + " ...\n";
- }
- return text;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimLeading(@NotNull String string) {
- return trimLeading((CharSequence)string).toString();
- }
- @NotNull
- @Contract(pure = true)
- public static CharSequence trimLeading(@NotNull CharSequence string) {
- int index = 0;
- while (index < string.length() && Character.isWhitespace(string.charAt(index))) index++;
- return string.subSequence(index, string.length());
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimLeading(@NotNull String string, char symbol) {
- int index = 0;
- while (index < string.length() && string.charAt(index) == symbol) index++;
- return string.substring(index);
- }
-
- @NotNull
- public static StringBuilder trimLeading(@NotNull StringBuilder builder, char symbol) {
- int index = 0;
- while (index < builder.length() && builder.charAt(index) == symbol) index++;
- if (index > 0) builder.delete(0, index);
- return builder;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimTrailing(@NotNull String string) {
- return trimTrailing((CharSequence)string).toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static CharSequence trimTrailing(@NotNull CharSequence string) {
- int index = string.length() - 1;
- while (index >= 0 && Character.isWhitespace(string.charAt(index))) index--;
- return string.subSequence(0, index + 1);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimTrailing(@NotNull String string, char symbol) {
- int index = string.length() - 1;
- while (index >= 0 && string.charAt(index) == symbol) index--;
- return string.substring(0, index + 1);
- }
-
- @NotNull
- public static StringBuilder trimTrailing(@NotNull StringBuilder builder, char symbol) {
- int index = builder.length() - 1;
- while (index >= 0 && builder.charAt(index) == symbol) index--;
- builder.setLength(index + 1);
- return builder;
- }
-
- @Contract(pure = true)
- public static boolean startsWithChar(@Nullable CharSequence s, char prefix) {
- return s != null && s.length() != 0 && s.charAt(0) == prefix;
- }
-
- @Contract(pure = true)
- public static boolean endsWithChar(@Nullable CharSequence s, char suffix) {
- return StringUtilRt.endsWithChar(s, suffix);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimStart(@NotNull String s, @NotNull String prefix) {
- if (s.startsWith(prefix)) {
- return s.substring(prefix.length());
- }
- return s;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimExtensions(@NotNull String name) {
- int index = name.indexOf('.');
- return index < 0 ? name : name.substring(0, index);
- }
+ @Contract(pure = true)
+ public static boolean equalsTrimWhitespaces(@NotNull CharSequence s1, @NotNull CharSequence s2) {
+ int start1 = 0;
+ int end1 = s1.length();
+ int end2 = s2.length();
-// @NotNull
-// @Contract(pure = true)
-// public static String pluralize(@NotNull String base, int count) {
-// if (count == 1) return base;
-// return pluralize(base);
-// }
+ while (start1 < end1) {
+ char c = s1.charAt(start1);
+ if (!isWhiteSpace(c)) break;
+ start1++;
+ }
- public static void repeatSymbol(@NotNull Appendable buffer, char symbol, int times) {
- assert times >= 0 : times;
- try {
- for (int i = 0; i < times; i++) {
- buffer.append(symbol);
- }
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
-
- @Contract(pure = true)
- public static String defaultIfEmpty(@Nullable String value, String defaultValue) {
- return isEmpty(value) ? defaultValue : value;
- }
-
- @Contract(value = "null -> false", pure = true)
- public static boolean isNotEmpty(@Nullable String s) {
- return !isEmpty(s);
- }
-
- @Contract(value = "null -> true", pure = true)
- public static boolean isEmpty(@Nullable String s) {
- return s == null || s.isEmpty();
- }
-
- @Contract(value = "null -> true",pure = true)
- public static boolean isEmpty(@Nullable CharSequence cs) {
- return StringUtilRt.isEmpty(cs);
- }
-
- @Contract(pure = true)
- public static int length(@Nullable CharSequence cs) {
- return cs == null ? 0 : cs.length();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String notNullize(@Nullable String s) {
- return StringUtilRt.notNullize(s);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String notNullize(@Nullable String s, @NotNull String defaultValue) {
- return StringUtilRt.notNullize(s, defaultValue);
- }
-
- @Nullable
- @Contract(pure = true)
- public static String nullize(@Nullable String s) {
- return nullize(s, false);
- }
-
- @Nullable
- @Contract(pure = true)
- public static String nullize(@Nullable String s, boolean nullizeSpaces) {
- boolean empty = nullizeSpaces ? isEmptyOrSpaces(s) : isEmpty(s);
- return empty ? null : s;
- }
-
- @Contract(value = "null -> true",pure = true)
- // we need to keep this method to preserve backward compatibility
- public static boolean isEmptyOrSpaces(@Nullable String s) {
- return isEmptyOrSpaces((CharSequence)s);
- }
-
- @Contract(value = "null -> true", pure = true)
- public static boolean isEmptyOrSpaces(@Nullable CharSequence s) {
- return StringUtilRt.isEmptyOrSpaces(s);
- }
-
- /**
- * Allows to answer if given symbol is white space, tabulation or line feed.
- *
- * @param c symbol to check
- * @return {@code true} if given symbol is white space, tabulation or line feed; {@code false} otherwise
- */
- @Contract(pure = true)
- public static boolean isWhiteSpace(char c) {
- return c == '\n' || c == '\t' || c == ' ';
- }
-
- @NotNull
- @Contract(pure = true)
- public static String getThrowableText(@NotNull Throwable aThrowable) {
- return ExceptionUtil.getThrowableText(aThrowable);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String repeatSymbol(final char aChar, final int count) {
- char[] buffer = new char[count];
- Arrays.fill(buffer, aChar);
- return StringFactory.createShared(buffer);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String repeat(@NotNull String s, int count) {
- assert count >= 0 : count;
- StringBuilder sb = new StringBuilder(s.length() * count);
- for (int i = 0; i < count; i++) {
- sb.append(s);
- }
- return sb.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static List split(@NotNull String s, @NotNull String separator) {
- return split(s, separator, true);
- }
- @NotNull
- @Contract(pure = true)
- public static List split(@NotNull CharSequence s, @NotNull CharSequence separator) {
- return split(s, separator, true, true);
- }
-
- @NotNull
- @Contract(pure = true)
- public static List split(@NotNull String s, @NotNull String separator, boolean excludeSeparator) {
- return split(s, separator, excludeSeparator, true);
- }
-
- @NotNull
- @Contract(pure = true)
- @SuppressWarnings("unchecked")
- public static List split(@NotNull String s, @NotNull String separator, boolean excludeSeparator, boolean excludeEmptyStrings) {
- return (List)split((CharSequence)s, separator, excludeSeparator, excludeEmptyStrings);
- }
-
- @NotNull
- @Contract(pure = true)
- public static List split(@NotNull CharSequence s, @NotNull CharSequence separator, boolean excludeSeparator, boolean excludeEmptyStrings) {
- if (separator.length() == 0) {
- return Collections.singletonList(s);
- }
- List result = new ArrayList();
- int pos = 0;
- while (true) {
- int index = indexOf(s, separator, pos);
- if (index == -1) break;
- final int nextPos = index + separator.length();
- CharSequence token = s.subSequence(pos, excludeSeparator ? index : nextPos);
- if (token.length() != 0 || !excludeEmptyStrings) {
- result.add(token);
- }
- pos = nextPos;
- }
- if (pos < s.length() || !excludeEmptyStrings && pos == s.length()) {
- result.add(s.subSequence(pos, s.length()));
- }
- return result;
- }
-
- @NotNull
- @Contract(pure = true)
- public static Iterable tokenize(@NotNull String s, @NotNull String separators) {
- final com.intellij.util.text.StringTokenizer tokenizer = new com.intellij.util.text.StringTokenizer(s, separators);
- return new Iterable() {
- @NotNull
- @Override
- public Iterator iterator() {
- return new Iterator() {
- @Override
- public boolean hasNext() {
- return tokenizer.hasMoreTokens();
- }
-
- @Override
- public String next() {
- return tokenizer.nextToken();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
- };
- }
-
- @NotNull
- @Contract(pure = true)
- public static Iterable tokenize(@NotNull final StringTokenizer tokenizer) {
- return new Iterable() {
- @NotNull
- @Override
- public Iterator iterator() {
- return new Iterator() {
- @Override
- public boolean hasNext() {
- return tokenizer.hasMoreTokens();
- }
-
- @Override
- public String next() {
- return tokenizer.nextToken();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
- };
- }
-
- /**
- * @return list containing all words in {@code text}, or {@link ContainerUtil#emptyList()} if there are none.
- * The word here means the maximum sub-string consisting entirely of characters which are {@code Character.isJavaIdentifierPart(c)}.
- */
- @NotNull
- @Contract(pure = true)
- public static List getWordsIn(@NotNull String text) {
- List result = null;
- int start = -1;
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- boolean isIdentifierPart = Character.isJavaIdentifierPart(c);
- if (isIdentifierPart && start == -1) {
- start = i;
- }
- if (isIdentifierPart && i == text.length() - 1) {
- if (result == null) {
- result = new SmartList();
+ while (start1 < end1) {
+ char c = s1.charAt(end1 - 1);
+ if (!isWhiteSpace(c)) break;
+ end1--;
}
- result.add(text.substring(start, i + 1));
- }
- else if (!isIdentifierPart && start != -1) {
- if (result == null) {
- result = new SmartList();
- }
- result.add(text.substring(start, i));
- start = -1;
- }
- }
- if (result == null) {
- return ContainerUtil.emptyList();
- }
- return result;
- }
-
- @NotNull
- @Contract(pure = true)
- public static List getWordIndicesIn(@NotNull String text) {
- return getWordIndicesIn(text, null);
- }
-
- /**
- * @param text text to get word ranges in.
- * @param separatorsSet if not null, only these characters will be considered as separators (i.e. not a part of word).
- * Otherwise {@link Character#isJavaIdentifierPart(char)} will be used to determine whether a symbol is part of word.
- * @return ranges ranges of words in passed text.
- */
- @NotNull
- @Contract(pure = true)
- public static List getWordIndicesIn(@NotNull String text, @Nullable Set separatorsSet) {
- List result = new SmartList();
- int start = -1;
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- boolean isIdentifierPart = separatorsSet == null ? Character.isJavaIdentifierPart(c) : !separatorsSet.contains(c);
- if (isIdentifierPart && start == -1) {
- start = i;
- }
- if (isIdentifierPart && i == text.length() - 1) {
- result.add(new TextRange(start, i + 1));
- }
- else if (!isIdentifierPart && start != -1) {
- result.add(new TextRange(start, i));
- start = -1;
- }
- }
- return result;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String join(@NotNull final String[] strings, @NotNull final String separator) {
- return join(strings, 0, strings.length, separator);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String join(@NotNull final String[] strings, int startIndex, int endIndex, @NotNull final String separator) {
- final StringBuilder result = new StringBuilder();
- for (int i = startIndex; i < endIndex; i++) {
- if (i > startIndex) result.append(separator);
- result.append(strings[i]);
- }
- return result.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String[] zip(@NotNull String[] strings1, @NotNull String[] strings2, String separator) {
- if (strings1.length != strings2.length) throw new IllegalArgumentException();
-
- String[] result = ArrayUtil.newStringArray(strings1.length);
- for (int i = 0; i < result.length; i++) {
- result[i] = strings1[i] + separator + strings2[i];
- }
-
- return result;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String[] surround(@NotNull String[] strings, @NotNull String prefix, @NotNull String suffix) {
- String[] result = ArrayUtil.newStringArray(strings.length);
- for (int i = 0; i < result.length; i++) {
- result[i] = prefix + strings[i] + suffix;
- }
- return result;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String join(@NotNull T[] items, @NotNull Function super T, String> f, @NotNull String separator) {
- return join(Arrays.asList(items), f, separator);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String join(@NotNull Collection extends T> items,
- @NotNull Function super T, String> f,
- @NotNull String separator) {
- if (items.isEmpty()) return "";
- if (items.size() == 1) return notNullize(f.fun(items.iterator().next()));
- return join((Iterable extends T>)items, f, separator);
- }
-
- @Contract(pure = true)
- public static String join(@NotNull Iterable> items, @NotNull String separator) {
- StringBuilder result = new StringBuilder();
- for (Object item : items) {
- result.append(item).append(separator);
- }
- if (result.length() > 0) {
- result.setLength(result.length() - separator.length());
- }
- return result.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String join(@NotNull Iterable extends T> items,
- @NotNull Function super T, String> f,
- @NotNull String separator) {
- StringBuilder result = new StringBuilder();
- join(items, f, separator, result);
- return result.toString();
- }
-
- public static void join(@NotNull Iterable extends T> items,
- @NotNull Function super T, String> f,
- @NotNull String separator,
- @NotNull StringBuilder result) {
- boolean isFirst = true;
- for (T item : items) {
- String string = f.fun(item);
- if (!isEmpty(string)) {
- if (isFirst) {
- isFirst = false;
+
+ int start2 = 0;
+ while (start2 < end2) {
+ char c = s2.charAt(start2);
+ if (!isWhiteSpace(c)) break;
+ start2++;
}
- else {
- result.append(separator);
+
+ while (start2 < end2) {
+ char c = s2.charAt(end2 - 1);
+ if (!isWhiteSpace(c)) break;
+ end2--;
}
- result.append(string);
- }
- }
- }
- @NotNull
- @Contract(pure = true)
- public static String join(@NotNull Collection strings, @NotNull String separator) {
- if (strings.size() <= 1) {
- return notNullize(ContainerUtil.getFirstItem(strings));
+ CharSequence ts1 = new CharSequenceSubSequence(s1, start1, end1);
+ CharSequence ts2 = new CharSequenceSubSequence(s2, start2, end2);
+
+ return equals(ts1, ts2);
}
- StringBuilder result = new StringBuilder();
- join(strings, separator, result);
- return result.toString();
- }
- public static void join(@NotNull Collection strings, @NotNull String separator, @NotNull StringBuilder result) {
- boolean isFirst = true;
- for (String string : strings) {
- if (string != null) {
- if (isFirst) {
- isFirst = false;
+ /**
+ * Collapses all white-space (including new lines) between non-white-space characters to a single space character.
+ * Leading and trailing white space is removed.
+ */
+ public static String collapseWhiteSpace(@NotNull CharSequence s) {
+ final StringBuilder result = new StringBuilder();
+ boolean space = false;
+ for (int i = 0, length = s.length(); i < length; i++) {
+ final char ch = s.charAt(i);
+ if (isWhiteSpace(ch)) {
+ if (!space) space = true;
+ }
+ else {
+ if (space && result.length() > 0) result.append(' ');
+ result.append(ch);
+ space = false;
+ }
}
- else {
- result.append(separator);
- }
- result.append(string);
- }
- }
- }
-
- @NotNull
- @Contract(pure = true)
- public static String join(@NotNull final int[] strings, @NotNull final String separator) {
- final StringBuilder result = new StringBuilder();
- for (int i = 0; i < strings.length; i++) {
- if (i > 0) result.append(separator);
- result.append(strings[i]);
- }
- return result.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String join(@NotNull final String... strings) {
- if (strings.length == 0) return "";
-
- final StringBuilder builder = new StringBuilder();
- for (final String string : strings) {
- builder.append(string);
- }
- return builder.toString();
- }
-
- /**
- * Consider using {@link StringUtil#unquoteString(String)} instead.
- * Note: this method has an odd behavior:
- * Quotes are removed even if leading and trailing quotes are different or
- * if there is only one quote (leading or trailing).
- */
- @NotNull
- @Contract(pure = true)
- public static String stripQuotesAroundValue(@NotNull String text) {
- final int len = text.length();
- if (len > 0) {
- final int from = isQuoteAt(text, 0) ? 1 : 0;
- final int to = len > 1 && isQuoteAt(text, len - 1) ? len - 1 : len;
- if (from > 0 || to < len) {
- return text.substring(from, to);
- }
- }
- return text;
- }
-
- /** Formats given duration as a sum of time units (example: {@code formatDuration(123456) = "2 m 3 s 456 ms"}). */
- @NotNull
- @Contract(pure = true)
- public static String formatDuration(long duration) {
- return formatDuration(duration, " ");
- }
-
- private static final String[] TIME_UNITS = {"ms", "s", "m", "h", "d", "mo", "yr", "c", "ml", "ep"};
- private static final long[] TIME_MULTIPLIERS = {1, 1000, 60, 60, 24, 30, 12, 100, 10, 10000};
-
- /** Formats given duration as a sum of time units (example: {@code formatDuration(123456, "") = "2m 3s 456ms"}). */
- @NotNull
- @Contract(pure = true)
- public static String formatDuration(long duration, @NotNull String unitSeparator) {
- String[] units = TIME_UNITS;
-
- StringBuilder sb = new StringBuilder();
- long count = duration;
- int i = 1;
- for (; i < units.length && count > 0; i++) {
- long multiplier = TIME_MULTIPLIERS[i];
- if (count < multiplier) break;
- long remainder = count % multiplier;
- count /= multiplier;
- if (remainder != 0 || sb.length() > 0) {
- if (!units[i - 1].isEmpty()) {
- sb.insert(0, units[i - 1]);
- sb.insert(0, unitSeparator);
- }
- sb.insert(0, remainder).insert(0, " ");
- }
- else {
- remainder = Math.round(remainder * 100 / (double)multiplier);
- count += remainder / 100;
- }
- }
- if (!units[i - 1].isEmpty()) {
- sb.insert(0, units[i - 1]);
- sb.insert(0, unitSeparator);
- }
- sb.insert(0, count);
- return sb.toString();
- }
-
- @Contract(pure = true)
- public static boolean containsAlphaCharacters(@NotNull String value) {
- for (int i = 0; i < value.length(); i++) {
- if (Character.isLetter(value.charAt(i))) return true;
- }
- return false;
- }
-
- @Contract(pure = true)
- public static boolean containsAnyChar(@NotNull final String value, @NotNull final String chars) {
- return chars.length() > value.length()
- ? containsAnyChar(value, chars, 0, value.length())
- : containsAnyChar(chars, value, 0, chars.length());
- }
-
- @Contract(pure = true)
- public static boolean containsAnyChar(@NotNull final String value,
- @NotNull final String chars,
- final int start, final int end) {
- for (int i = start; i < end; i++) {
- if (chars.indexOf(value.charAt(i)) >= 0) {
- return true;
- }
- }
-
- return false;
- }
-
- @Contract(pure = true)
- public static boolean containsChar(@NotNull final String value, final char ch) {
- return value.indexOf(ch) >= 0;
- }
-
- /**
- * @deprecated use #capitalize(String)
- */
- @Deprecated
- @Contract(value = "null -> null; !null -> !null", pure = true)
- public static String firstLetterToUpperCase(@Nullable final String displayString) {
- if (displayString == null || displayString.isEmpty()) return displayString;
- char firstChar = displayString.charAt(0);
- char uppedFirstChar = toUpperCase(firstChar);
-
- if (uppedFirstChar == firstChar) return displayString;
-
- char[] buffer = displayString.toCharArray();
- buffer[0] = uppedFirstChar;
- return StringFactory.createShared(buffer);
- }
-
- /**
- * Strip out all characters not accepted by given filter
- *
- * @param s e.g. "/n my string "
- * @param filter e.g. {@link CharFilter#NOT_WHITESPACE_FILTER}
- * @return stripped string e.g. "mystring"
- */
- @NotNull
- @Contract(pure = true)
- public static String strip(@NotNull final String s, @NotNull final CharFilter filter) {
- final StringBuilder result = new StringBuilder(s.length());
- for (int i = 0; i < s.length(); i++) {
- char ch = s.charAt(i);
- if (filter.accept(ch)) {
- result.append(ch);
- }
- }
- return result.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static List findMatches(@NotNull String s, @NotNull Pattern pattern) {
- return findMatches(s, pattern, 1);
- }
-
- @NotNull
- @Contract(pure = true)
- public static List findMatches(@NotNull String s, @NotNull Pattern pattern, int groupIndex) {
- List result = new SmartList();
- Matcher m = pattern.matcher(s);
- while (m.find()) {
- String group = m.group(groupIndex);
- if (group != null) {
- result.add(group);
- }
- }
- return result;
- }
-
- /**
- * Find position of the first character accepted by given filter.
- *
- * @param s the string to search
- * @param filter search filter
- * @return position of the first character accepted or -1 if not found
- */
- @Contract(pure = true)
- public static int findFirst(@NotNull final CharSequence s, @NotNull CharFilter filter) {
- for (int i = 0; i < s.length(); i++) {
- char ch = s.charAt(i);
- if (filter.accept(ch)) {
- return i;
- }
- }
- return -1;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String replaceSubstring(@NotNull String string, @NotNull TextRange range, @NotNull String replacement) {
- return range.replace(string, replacement);
- }
-
- @Contract(pure = true)
- public static boolean startsWithWhitespace(@NotNull String text) {
- return !text.isEmpty() && Character.isWhitespace(text.charAt(0));
- }
-
- @Contract(pure = true)
- public static boolean isChar(CharSequence seq, int index, char c) {
- return index >= 0 && index < seq.length() && seq.charAt(index) == c;
- }
-
- @Contract(pure = true)
- public static boolean startsWith(@NotNull CharSequence text, @NotNull CharSequence prefix) {
- int l1 = text.length();
- int l2 = prefix.length();
- if (l1 < l2) return false;
-
- for (int i = 0; i < l2; i++) {
- if (text.charAt(i) != prefix.charAt(i)) return false;
- }
-
- return true;
- }
-
- @Contract(pure = true)
- public static boolean startsWith(@NotNull CharSequence text, int startIndex, @NotNull CharSequence prefix) {
- int tl = text.length();
- if (startIndex < 0 || startIndex > tl) {
- throw new IllegalArgumentException("Index is out of bounds: " + startIndex + ", length: " + tl);
- }
- int l1 = tl - startIndex;
- int l2 = prefix.length();
- if (l1 < l2) return false;
-
- for (int i = 0; i < l2; i++) {
- if (text.charAt(i + startIndex) != prefix.charAt(i)) return false;
- }
-
- return true;
- }
-
- @Contract(pure = true)
- public static boolean endsWith(@NotNull CharSequence text, @NotNull CharSequence suffix) {
- int l1 = text.length();
- int l2 = suffix.length();
- if (l1 < l2) return false;
-
- for (int i = l1 - 1; i >= l1 - l2; i--) {
- if (text.charAt(i) != suffix.charAt(i + l2 - l1)) return false;
- }
-
- return true;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String commonPrefix(@NotNull String s1, @NotNull String s2) {
- return s1.substring(0, commonPrefixLength(s1, s2));
- }
-
- @Contract(pure = true)
- public static int commonPrefixLength(@NotNull CharSequence s1, @NotNull CharSequence s2) {
- return commonPrefixLength(s1, s2, false);
- }
-
- @Contract(pure = true)
- public static int commonPrefixLength(@NotNull CharSequence s1, @NotNull CharSequence s2, boolean ignoreCase) {
- int i;
- int minLength = Math.min(s1.length(), s2.length());
- for (i = 0; i < minLength; i++) {
- if (!charsMatch(s1.charAt(i), s2.charAt(i), ignoreCase)) {
- break;
- }
- }
- return i;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String commonSuffix(@NotNull String s1, @NotNull String s2) {
- return s1.substring(s1.length() - commonSuffixLength(s1, s2));
- }
-
- @Contract(pure = true)
- public static int commonSuffixLength(@NotNull CharSequence s1, @NotNull CharSequence s2) {
- int s1Length = s1.length();
- int s2Length = s2.length();
- if (s1Length == 0 || s2Length == 0) return 0;
- int i;
- for (i = 0; i < s1Length && i < s2Length; i++) {
- if (s1.charAt(s1Length - i - 1) != s2.charAt(s2Length - i - 1)) {
- break;
- }
- }
- return i;
- }
-
- /**
- * Allows to answer if target symbol is contained at given char sequence at {@code [start; end)} interval.
- *
- * @param s target char sequence to check
- * @param start start offset to use within the given char sequence (inclusive)
- * @param end end offset to use within the given char sequence (exclusive)
- * @param c target symbol to check
- * @return {@code true} if given symbol is contained at the target range of the given char sequence;
- * {@code false} otherwise
- */
- @Contract(pure = true)
- public static boolean contains(@NotNull CharSequence s, int start, int end, char c) {
- return indexOf(s, c, start, end) >= 0;
- }
-
- @Contract(pure = true)
- public static boolean containsWhitespaces(@Nullable CharSequence s) {
- if (s == null) return false;
-
- for (int i = 0; i < s.length(); i++) {
- if (Character.isWhitespace(s.charAt(i))) return true;
- }
- return false;
- }
-
- @Contract(pure = true)
- public static int indexOf(@NotNull CharSequence s, char c) {
- return indexOf(s, c, 0, s.length());
- }
-
- @Contract(pure = true)
- public static int indexOf(@NotNull CharSequence s, char c, int start) {
- return indexOf(s, c, start, s.length());
- }
-
- @Contract(pure = true)
- public static int indexOf(@NotNull CharSequence s, char c, int start, int end) {
- end = Math.min(end, s.length());
- for (int i = Math.max(start, 0); i < end; i++) {
- if (s.charAt(i) == c) return i;
- }
- return -1;
- }
-
- @Contract(pure = true)
- public static boolean contains(@NotNull CharSequence sequence, @NotNull CharSequence infix) {
- return indexOf(sequence, infix) >= 0;
- }
-
- @Contract(pure = true)
- public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix) {
- return indexOf(sequence, infix, 0);
- }
-
- @Contract(pure = true)
- public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix, int start) {
- return indexOf(sequence, infix, start, sequence.length());
- }
-
- @Contract(pure = true)
- public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix, int start, int end) {
- for (int i = start; i <= end - infix.length(); i++) {
- if (startsWith(sequence, i, infix)) {
- return i;
- }
- }
- return -1;
- }
-
- @Contract(pure = true)
- public static int indexOf(@NotNull CharSequence s, char c, int start, int end, boolean caseSensitive) {
- end = Math.min(end, s.length());
- for (int i = Math.max(start, 0); i < end; i++) {
- if (charsMatch(s.charAt(i), c, !caseSensitive)) return i;
- }
- return -1;
- }
-
- @Contract(pure = true)
- public static int indexOf(@NotNull char[] s, char c, int start, int end, boolean caseSensitive) {
- end = Math.min(end, s.length);
- for (int i = Math.max(start, 0); i < end; i++) {
- if (charsMatch(s[i], c, !caseSensitive)) return i;
- }
- return -1;
- }
-
- @Contract(pure = true)
- public static int indexOfSubstringEnd(@NotNull String text, @NotNull String subString) {
- int i = text.indexOf(subString);
- if (i == -1) return -1;
- return i + subString.length();
- }
-
- @Contract(pure = true)
- public static int indexOfAny(@NotNull final String s, @NotNull final String chars) {
- return indexOfAny(s, chars, 0, s.length());
- }
-
- @Contract(pure = true)
- public static int indexOfAny(@NotNull final CharSequence s, @NotNull final String chars) {
- return indexOfAny(s, chars, 0, s.length());
- }
-
- @Contract(pure = true)
- public static int indexOfAny(@NotNull final String s, @NotNull final String chars, final int start, final int end) {
- return indexOfAny((CharSequence)s, chars, start, end);
- }
-
- @Contract(pure = true)
- public static int indexOfAny(@NotNull final CharSequence s, @NotNull final String chars, final int start, int end) {
- end = Math.min(end, s.length());
- for (int i = Math.max(start, 0); i < end; i++) {
- if (containsChar(chars, s.charAt(i))) return i;
- }
- return -1;
- }
-
- @Contract(pure = true)
- public static int lastIndexOfAny(@NotNull CharSequence s, @NotNull final String chars) {
- for (int i = s.length() - 1; i >= 0; i--) {
- if (containsChar(chars, s.charAt(i))) return i;
- }
- return -1;
- }
-
- @Nullable
- @Contract(pure = true)
- public static String substringBefore(@NotNull String text, @NotNull String subString) {
- int i = text.indexOf(subString);
- if (i == -1) return null;
- return text.substring(0, i);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String substringBeforeLast(@NotNull String text, @NotNull String subString) {
- int i = text.lastIndexOf(subString);
- if (i == -1) return text;
- return text.substring(0, i);
- }
-
- @Nullable
- @Contract(pure = true)
- public static String substringAfter(@NotNull String text, @NotNull String subString) {
- int i = text.indexOf(subString);
- if (i == -1) return null;
- return text.substring(i + subString.length());
- }
-
- @Nullable
- @Contract(pure = true)
- public static String substringAfterLast(@NotNull String text, @NotNull String subString) {
- int i = text.lastIndexOf(subString);
- if (i == -1) return null;
- return text.substring(i + subString.length());
- }
-
- /**
- * Allows to retrieve index of last occurrence of the given symbols at {@code [start; end)} sub-sequence of the given text.
- *
- * @param s target text
- * @param c target symbol which last occurrence we want to check
- * @param start start offset of the target text (inclusive)
- * @param end end offset of the target text (exclusive)
- * @return index of the last occurrence of the given symbol at the target sub-sequence of the given text if any;
- * {@code -1} otherwise
- */
- @Contract(pure = true)
- public static int lastIndexOf(@NotNull CharSequence s, char c, int start, int end) {
- return StringUtilRt.lastIndexOf(s, c, start, end);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String first(@NotNull String text, final int maxLength, final boolean appendEllipsis) {
- return text.length() > maxLength ? text.substring(0, maxLength) + (appendEllipsis ? "..." : "") : text;
- }
-
- @NotNull
- @Contract(pure = true)
- public static CharSequence first(@NotNull CharSequence text, final int length, final boolean appendEllipsis) {
- if (text.length() <= length) {
- return text;
- }
- if (appendEllipsis) {
- return text.subSequence(0, length) + "...";
- }
- return text.subSequence(0, length);
- }
-
- @NotNull
- @Contract(pure = true)
- public static CharSequence last(@NotNull CharSequence text, final int length, boolean prependEllipsis) {
- if (text.length() <= length) {
- return text;
- }
- if (prependEllipsis) {
- return "..." + text.subSequence(text.length() - length, text.length());
- }
- return text.subSequence(text.length() - length, text.length());
- }
-
- @NotNull
- @Contract(pure = true)
- public static String firstLast(@NotNull String text, int length) {
- return text.length() > length
- ? text.subSequence(0, length / 2) + "\u2026" + text.subSequence(text.length() - length / 2 - 1, text.length())
- : text;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String escapeChar(@NotNull final String str, final char character) {
- return escapeChars(str, character);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String escapeChars(@NotNull final String str, final char... character) {
- final StringBuilder buf = new StringBuilder(str);
- for (char c : character) {
- escapeChar(buf, c);
- }
- return buf.toString();
- }
-
- public static void escapeChar(@NotNull final StringBuilder buf, final char character) {
- int idx = 0;
- while ((idx = indexOf(buf, character, idx)) >= 0) {
- buf.insert(idx, "\\");
- idx += 2;
- }
- }
-
- @NotNull
- @Contract(pure = true)
- public static String escapeQuotes(@NotNull final String str) {
- return escapeChar(str, '"');
- }
-
- public static void escapeQuotes(@NotNull final StringBuilder buf) {
- escapeChar(buf, '"');
- }
-
- @NotNull
- @Contract(pure = true)
- public static String escapeSlashes(@NotNull final String str) {
- return escapeChar(str, '/');
- }
-
- @NotNull
- @Contract(pure = true)
- public static String escapeBackSlashes(@NotNull final String str) {
- return escapeChar(str, '\\');
- }
-
- public static void escapeSlashes(@NotNull final StringBuilder buf) {
- escapeChar(buf, '/');
- }
-
- @NotNull
- @Contract(pure = true)
- public static String unescapeSlashes(@NotNull final String str) {
- final StringBuilder buf = new StringBuilder(str.length());
- unescapeChar(buf, str, '/');
- return buf.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String unescapeBackSlashes(@NotNull final String str) {
- final StringBuilder buf = new StringBuilder(str.length());
- unescapeChar(buf, str, '\\');
- return buf.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String unescapeChar(@NotNull final String str, char unescapeChar) {
- final StringBuilder buf = new StringBuilder(str.length());
- unescapeChar(buf, str, unescapeChar);
- return buf.toString();
- }
-
- private static void unescapeChar(@NotNull StringBuilder buf, @NotNull String str, char unescapeChar) {
- final int length = str.length();
- final int last = length - 1;
- for (int i = 0; i < length; i++) {
- char ch = str.charAt(i);
- if (ch == '\\' && i != last) {
- //noinspection AssignmentToForLoopParameter
- i++;
- ch = str.charAt(i);
- if (ch != unescapeChar) buf.append('\\');
- }
-
- buf.append(ch);
- }
- }
-
- public static void quote(@NotNull final StringBuilder builder) {
- quote(builder, '\"');
- }
-
- public static void quote(@NotNull final StringBuilder builder, final char quotingChar) {
- builder.insert(0, quotingChar);
- builder.append(quotingChar);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String wrapWithDoubleQuote(@NotNull String str) {
- return '\"' + str + "\"";
- }
-
- private static final List REPLACES_REFS = Arrays.asList("<", ">", "&", "'", """);
- private static final List REPLACES_DISP = Arrays.asList("<", ">", "&", "'", "\"");
-
- /**
- * @deprecated Use {@link #unescapeXmlEntities(String)} instead
- */
- @Contract(value = "null -> null; !null -> !null",pure = true)
- @Deprecated
- public static String unescapeXml(@Nullable final String text) {
- return text == null ? null : unescapeXmlEntities(text);
- }
-
- /**
- * @deprecated Use {@link #escapeXmlEntities(String)} instead
- */
- @Contract(value = "null -> null; !null -> !null",pure = true)
- @Deprecated
- public static String escapeXml(@Nullable final String text) {
- return text == null ? null : escapeXmlEntities(text);
- }
-
- /**
- * @return {@code text} with some standard XML entities replaced with corresponding characters, e.g. '{@code <}' replaced with '<'
- */
- @NotNull
- @Contract(pure = true)
- public static String unescapeXmlEntities(@NotNull String text) {
- return replace(text, REPLACES_REFS, REPLACES_DISP);
- }
-
- /**
- * @return {@code text} with some characters replaced with standard XML entities, e.g. '<' replaced with '{@code <}'
- */
- @NotNull
- @Contract(pure = true)
- public static String escapeXmlEntities(@NotNull String text) {
- return replace(text, REPLACES_DISP, REPLACES_REFS);
- }
-
- @NotNull
- public static String removeHtmlTags(@NotNull String htmlString) {
- return removeHtmlTags(htmlString, false);
- }
-
- @NotNull
- public static String removeHtmlTags(@NotNull String htmlString, boolean isRemoveStyleTag) {
- if (isEmpty(htmlString)) {
- return "";
- }
-
- final MyHtml2Text parser = isRemoveStyleTag ? new MyHtml2Text(true) : html2TextParser;
- try {
- parser.parse(new StringReader(htmlString));
- }
- catch (IOException e) {
- LOG.error(e);
- }
- return parser.getText();
- }
-
- private static final List MN_QUOTED = Arrays.asList("&&", "__");
- private static final List MN_CHARS = Arrays.asList("&", "_");
-
- @NotNull
- @Contract(pure = true)
- public static String escapeMnemonics(@NotNull String text) {
- return replace(text, MN_CHARS, MN_QUOTED);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String htmlEmphasize(@NotNull String text) {
- return "" + escapeXmlEntities(text) + "";
- }
-
-
- @NotNull
- @Contract(pure = true)
- public static String escapeToRegexp(@NotNull String text) {
- final StringBuilder result = new StringBuilder(text.length());
- return escapeToRegexp(text, result).toString();
- }
-
- @NotNull
- public static StringBuilder escapeToRegexp(@NotNull CharSequence text, @NotNull StringBuilder builder) {
- for (int i = 0; i < text.length(); i++) {
- final char c = text.charAt(i);
- if (c == ' ' || Character.isLetter(c) || Character.isDigit(c) || c == '_') {
- builder.append(c);
- }
- else if (c == '\n') {
- builder.append("\\n");
- }
- else if (c == '\r') {
- builder.append("\\r");
- }
- else {
- builder.append('\\').append(c);
- }
- }
-
- return builder;
- }
-
- @Contract(pure = true)
- public static boolean isEscapedBackslash(@NotNull char[] chars, int startOffset, int backslashOffset) {
- if (chars[backslashOffset] != '\\') {
- return true;
- }
- boolean escaped = false;
- for (int i = startOffset; i < backslashOffset; i++) {
- if (chars[i] == '\\') {
- escaped = !escaped;
- }
- else {
- escaped = false;
- }
- }
- return escaped;
- }
-
- @Contract(pure = true)
- public static boolean isEscapedBackslash(@NotNull CharSequence text, int startOffset, int backslashOffset) {
- if (text.charAt(backslashOffset) != '\\') {
- return true;
- }
- boolean escaped = false;
- for (int i = startOffset; i < backslashOffset; i++) {
- if (text.charAt(i) == '\\') {
- escaped = !escaped;
- }
- else {
- escaped = false;
- }
- }
- return escaped;
- }
-
- /**
- * @deprecated Use {@link #replace(String, List, List)}
- */
- @Deprecated
- @NotNull
- @Contract(pure = true)
- public static String replace(@NotNull String text, @NotNull String[] from, @NotNull String[] to) {
- return replace(text, Arrays.asList(from), Arrays.asList(to));
- }
-
- @NotNull
- @Contract(pure = true)
- public static String replace(@NotNull String text, @NotNull List from, @NotNull List to) {
- assert from.size() == to.size();
- StringBuilder result = null;
- replace:
- for (int i = 0; i < text.length(); i++) {
- for (int j = 0; j < from.size(); j += 1) {
- String toReplace = from.get(j);
- String replaceWith = to.get(j);
-
- final int len = toReplace.length();
- if (text.regionMatches(i, toReplace, 0, len)) {
- if (result == null) {
- result = new StringBuilder(text.length());
- result.append(text, 0, i);
- }
- result.append(replaceWith);
- //noinspection AssignmentToForLoopParameter
- i += len - 1;
- continue replace;
- }
- }
-
- if (result != null) {
- result.append(text.charAt(i));
- }
- }
- return result == null ? text : result.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String[] filterEmptyStrings(@NotNull String[] strings) {
- int emptyCount = 0;
- for (String string : strings) {
- if (string == null || string.isEmpty()) emptyCount++;
- }
- if (emptyCount == 0) return strings;
-
- String[] result = ArrayUtil.newStringArray(strings.length - emptyCount);
- int count = 0;
- for (String string : strings) {
- if (string == null || string.isEmpty()) continue;
- result[count++] = string;
- }
-
- return result;
- }
-
- @Contract(pure = true)
- public static int countNewLines(@NotNull CharSequence text) {
- return countChars(text, '\n');
- }
-
- @Contract(pure = true)
- public static int countChars(@NotNull CharSequence text, char c) {
- return countChars(text, c, 0, false);
- }
-
- @Contract(pure = true)
- public static int countChars(@NotNull CharSequence text, char c, int offset, boolean stopAtOtherChar) {
- return countChars(text, c, offset, text.length(), stopAtOtherChar);
- }
-
- @Contract(pure = true)
- public static int countChars(@NotNull CharSequence text, char c, int start, int end, boolean stopAtOtherChar) {
- boolean forward = start <= end;
- start = forward ? Math.max(0, start) : Math.min(text.length(), start);
- end = forward ? Math.min(text.length(), end) : Math.max(0, end);
- int count = 0;
- for (int i = forward ? start : start - 1; forward == i < end; i += forward ? 1 : -1) {
- if (text.charAt(i) == c) {
- count++;
- }
- else if (stopAtOtherChar) {
- break;
- }
- }
- return count;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String capitalsOnly(@NotNull String s) {
- StringBuilder b = new StringBuilder();
- for (int i = 0; i < s.length(); i++) {
- if (Character.isUpperCase(s.charAt(i))) {
- b.append(s.charAt(i));
- }
- }
-
- return b.toString();
- }
-
- /**
- * @param args Strings to join.
- * @return {@code null} if any of given Strings is {@code null}.
- */
- @Nullable
- @Contract(pure = true)
- public static String joinOrNull(@NotNull String... args) {
- StringBuilder r = new StringBuilder();
- for (String arg : args) {
- if (arg == null) return null;
- r.append(arg);
- }
- return r.toString();
- }
-
- @Nullable
- @Contract(pure = true)
- public static String getPropertyName(@NotNull String methodName) {
- if (methodName.startsWith("get")) {
- return Introspector.decapitalize(methodName.substring(3));
- }
- if (methodName.startsWith("is")) {
- return Introspector.decapitalize(methodName.substring(2));
- }
- if (methodName.startsWith("set")) {
- return Introspector.decapitalize(methodName.substring(3));
- }
- return null;
- }
-
- @Contract(pure = true)
- public static boolean isJavaIdentifierStart(char c) {
- return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || Character.isJavaIdentifierStart(c);
- }
-
- @Contract(pure = true)
- public static boolean isJavaIdentifierPart(char c) {
- return c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || Character.isJavaIdentifierPart(c);
- }
-
- @Contract(pure = true)
- public static boolean isJavaIdentifier(@NotNull String text) {
- int len = text.length();
- if (len == 0) return false;
-
- if (!isJavaIdentifierStart(text.charAt(0))) return false;
-
- for (int i = 1; i < len; i++) {
- if (!isJavaIdentifierPart(text.charAt(i))) return false;
- }
-
- return true;
- }
-
- /**
- * Escape property name or key in property file. Unicode characters are escaped as well.
- *
- * @param input an input to escape
- * @param isKey if true, the rules for key escaping are applied. The leading space is escaped in that case.
- * @return an escaped string
- */
- @NotNull
- @Contract(pure = true)
- public static String escapeProperty(@NotNull String input, final boolean isKey) {
- final StringBuilder escaped = new StringBuilder(input.length());
- for (int i = 0; i < input.length(); i++) {
- final char ch = input.charAt(i);
- switch (ch) {
- case ' ':
- if (isKey && i == 0) {
- // only the leading space has to be escaped
- escaped.append('\\');
- }
- escaped.append(' ');
- break;
- case '\t':
- escaped.append("\\t");
- break;
- case '\r':
- escaped.append("\\r");
- break;
- case '\n':
- escaped.append("\\n");
- break;
- case '\f':
- escaped.append("\\f");
- break;
- case '\\':
- case '#':
- case '!':
- case ':':
- case '=':
- escaped.append('\\');
- escaped.append(ch);
- break;
- default:
- if (20 < ch && ch < 0x7F) {
- escaped.append(ch);
- }
- else {
- escaped.append("\\u");
- escaped.append(Character.forDigit((ch >> 12) & 0xF, 16));
- escaped.append(Character.forDigit((ch >> 8) & 0xF, 16));
- escaped.append(Character.forDigit((ch >> 4) & 0xF, 16));
- escaped.append(Character.forDigit((ch) & 0xF, 16));
- }
- break;
- }
- }
- return escaped.toString();
- }
-
- @NotNull
- @Contract(pure = true)
- public static String getQualifiedName(@Nullable String packageName, @NotNull String className) {
- if (packageName == null || packageName.isEmpty()) {
- return className;
- }
- return packageName + '.' + className;
- }
-
- @Contract(pure = true)
- public static int compareVersionNumbers(@Nullable String v1, @Nullable String v2) {
- // todo duplicates com.intellij.util.text.VersionComparatorUtil.compare
- // todo please refactor next time you make changes here
- if (v1 == null && v2 == null) {
- return 0;
- }
- if (v1 == null) {
- return -1;
- }
- if (v2 == null) {
- return 1;
- }
-
- String[] part1 = v1.split("[._\\-]");
- String[] part2 = v2.split("[._\\-]");
-
- int idx = 0;
- for (; idx < part1.length && idx < part2.length; idx++) {
- String p1 = part1[idx];
- String p2 = part2[idx];
-
- int cmp;
- if (p1.matches("\\d+") && p2.matches("\\d+")) {
- cmp = new Integer(p1).compareTo(new Integer(p2));
- }
- else {
- cmp = part1[idx].compareTo(part2[idx]);
- }
- if (cmp != 0) return cmp;
- }
-
- if (part1.length != part2.length) {
- boolean left = part1.length > idx;
- String[] parts = left ? part1 : part2;
-
- for (; idx < parts.length; idx++) {
- String p = parts[idx];
- int cmp;
- if (p.matches("\\d+")) {
- cmp = new Integer(p).compareTo(0);
+ return result.toString();
+ }
+
+ @Contract(pure = true)
+ public static boolean findIgnoreCase(@Nullable String toFind, @NotNull String... where) {
+ for (String string : where) {
+ if (equalsIgnoreCase(toFind, string)) return true;
}
- else {
- cmp = 1;
- }
- if (cmp != 0) return left ? cmp : -cmp;
- }
- }
- return 0;
- }
-
- @Contract(pure = true)
- public static int getOccurrenceCount(@NotNull String text, final char c) {
- int res = 0;
- int i = 0;
- while (i < text.length()) {
- i = text.indexOf(c, i);
- if (i >= 0) {
- res++;
- i++;
- }
- else {
- break;
- }
- }
- return res;
- }
-
- @Contract(pure = true)
- public static int getOccurrenceCount(@NotNull String text, @NotNull String s) {
- int res = 0;
- int i = 0;
- while (i < text.length()) {
- i = text.indexOf(s, i);
- if (i >= 0) {
- res++;
- i++;
- }
- else {
- break;
- }
- }
- return res;
- }
-
- @Contract(pure = true)
- public static int getIgnoreCaseOccurrenceCount(@NotNull String text, @NotNull String s) {
- int res = 0;
- int i = 0;
- while (i < text.length()) {
- i = indexOfIgnoreCase(text, s, i);
- if (i >= 0) {
- res++;
- i++;
- }
- else {
- break;
- }
- }
- return res;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String fixVariableNameDerivedFromPropertyName(@NotNull String name) {
- if (isEmptyOrSpaces(name)) return name;
- char c = name.charAt(0);
- if (isVowel(c)) {
- return "an" + Character.toUpperCase(c) + name.substring(1);
- }
- return "a" + Character.toUpperCase(c) + name.substring(1);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String sanitizeJavaIdentifier(@NotNull String name) {
- final StringBuilder result = new StringBuilder(name.length());
-
- for (int i = 0; i < name.length(); i++) {
- final char ch = name.charAt(i);
- if (Character.isJavaIdentifierPart(ch)) {
- if (result.length() == 0 && !Character.isJavaIdentifierStart(ch)) {
- result.append("_");
- }
- result.append(ch);
- }
- }
-
- return result.toString();
- }
-
- public static void assertValidSeparators(@NotNull CharSequence s) {
- char[] chars = CharArrayUtil.fromSequenceWithoutCopying(s);
- int slashRIndex = -1;
-
- if (chars != null) {
- for (int i = 0, len = s.length(); i < len; ++i) {
- if (chars[i] == '\r') {
- slashRIndex = i;
- break;
- }
- }
- }
- else {
- for (int i = 0, len = s.length(); i < len; i++) {
- if (s.charAt(i) == '\r') {
- slashRIndex = i;
- break;
- }
- }
- }
-
- if (slashRIndex != -1) {
- String context =
- String.valueOf(last(s.subSequence(0, slashRIndex), 10, true)) + first(s.subSequence(slashRIndex, s.length()), 10, true);
- context = escapeStringCharacters(context);
- throw new AssertionError("Wrong line separators: '" + context + "' at offset " + slashRIndex);
- }
- }
-
- @NotNull
- @Contract(pure = true)
- public static String tail(@NotNull String s, final int idx) {
- return idx >= s.length() ? "" : s.substring(idx);
- }
-
- /**
- * Splits string by lines.
- *
- * @param string String to split
- * @return array of strings
- */
- @NotNull
- @Contract(pure = true)
- public static String[] splitByLines(@NotNull String string) {
- return splitByLines(string, true);
- }
-
- /**
- * Splits string by lines. If several line separators are in a row corresponding empty lines
- * are also added to result if {@code excludeEmptyStrings} is {@code false}.
- *
- * @param string String to split
- * @return array of strings
- */
- @NotNull
- @Contract(pure = true)
- public static String[] splitByLines(@NotNull String string, boolean excludeEmptyStrings) {
- return (excludeEmptyStrings ? EOL_SPLIT_PATTERN : EOL_SPLIT_PATTERN_WITH_EMPTY).split(string);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String[] splitByLinesDontTrim(@NotNull String string) {
- return EOL_SPLIT_DONT_TRIM_PATTERN.split(string);
- }
-
- /**
- * Splits string by lines, keeping all line separators at the line ends and in the empty lines.
- *
E.g. splitting text
- *
- * foo\r\n
- * \n
- * bar\n
- * \r\n
- * baz\r
- * \r
- *
- * will return the following array: foo\r\n, \n, bar\n, \r\n, baz\r, \r
- *
- */
- @NotNull
- @Contract(pure = true)
- public static String[] splitByLinesKeepSeparators(@NotNull String string) {
- return EOL_SPLIT_KEEP_SEPARATORS.split(string);
- }
-
- @NotNull
- @Contract(pure = true)
- public static List> getWordsWithOffset(@NotNull String s) {
- List> res = ContainerUtil.newArrayList();
- s += " ";
- StringBuilder name = new StringBuilder();
- int startInd = -1;
- for (int i = 0; i < s.length(); i++) {
- if (Character.isWhitespace(s.charAt(i))) {
- if (name.length() > 0) {
- res.add(Pair.create(name.toString(), startInd));
- name.setLength(0);
- startInd = -1;
- }
- }
- else {
- if (startInd == -1) {
- startInd = i;
- }
- name.append(s.charAt(i));
- }
- }
- return res;
- }
-
- @Contract(pure = true)
- public static int naturalCompare(@Nullable String string1, @Nullable String string2) {
- return NaturalComparator.INSTANCE.compare(string1, string2);
- }
-
- @Contract(pure = true)
- public static boolean isDecimalDigit(char c) {
- return c >= '0' && c <= '9';
- }
-
- @Contract("null -> false")
- public static boolean isNotNegativeNumber(@Nullable CharSequence s) {
- if (s == null) {
- return false;
- }
- for (int i = 0; i < s.length(); i++) {
- if (!isDecimalDigit(s.charAt(i))) {
return false;
- }
}
- return true;
- }
-
- @Contract(pure = true)
- public static int compare(@Nullable String s1, @Nullable String s2, boolean ignoreCase) {
- //noinspection StringEquality
- if (s1 == s2) return 0;
- if (s1 == null) return -1;
- if (s2 == null) return 1;
- return ignoreCase ? s1.compareToIgnoreCase(s2) : s1.compareTo(s2);
- }
-
- @Contract(pure = true)
- public static int comparePairs(@Nullable String s1, @Nullable String t1, @Nullable String s2, @Nullable String t2, boolean ignoreCase) {
- final int compare = compare(s1, s2, ignoreCase);
- return compare != 0 ? compare : compare(t1, t2, ignoreCase);
- }
- @Contract(pure = true)
- public static int hashCode(@NotNull CharSequence s) {
- return stringHashCode(s);
- }
-
- @Contract(pure = true)
- public static boolean equals(@Nullable CharSequence s1, @Nullable CharSequence s2) {
- if (s1 == null ^ s2 == null) {
- return false;
+ @Contract(pure = true)
+ public static int compare(char c1, char c2, boolean ignoreCase) {
+ // duplicating String.equalsIgnoreCase logic
+ int d = c1 - c2;
+ if (d == 0 || !ignoreCase) {
+ return d;
+ }
+ // If characters don't match but case may be ignored,
+ // try converting both characters to uppercase.
+ // If the results match, then the comparison scan should
+ // continue.
+ char u1 = StringUtilRt.toUpperCase(c1);
+ char u2 = StringUtilRt.toUpperCase(c2);
+ d = u1 - u2;
+ if (d != 0) {
+ // Unfortunately, conversion to uppercase does not work properly
+ // for the Georgian alphabet, which has strange rules about case
+ // conversion. So we need to make one last check before
+ // exiting.
+ d = StringUtilRt.toLowerCase(u1) - StringUtilRt.toLowerCase(u2);
+ }
+ return d;
}
- if (s1 == null) {
- return true;
+ @Contract(pure = true)
+ public static boolean charsMatch(char c1, char c2, boolean ignoreCase) {
+ return compare(c1, c2, ignoreCase) == 0;
}
- if (s1.length() != s2.length()) {
- return false;
+ @NotNull
+ @Contract(pure = true)
+ public static String formatLinks(@NotNull String message) {
+ Pattern linkPattern = Pattern.compile("http://[a-zA-Z0-9./\\-+]+");
+ StringBuffer result = new StringBuffer();
+ Matcher m = linkPattern.matcher(message);
+ while (m.find()) {
+ m.appendReplacement(result, "" + m.group() + "");
+ }
+ m.appendTail(result);
+ return result.toString();
}
- for (int i = 0; i < s1.length(); i++) {
- if (s1.charAt(i) != s2.charAt(i)) {
- return false;
- }
+
+ @Contract(pure = true)
+ public static boolean isHexDigit(char c) {
+ return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F';
}
- return true;
- }
- @Contract(pure = true)
- public static boolean equalsIgnoreCase(@Nullable CharSequence s1, @Nullable CharSequence s2) {
- if (s1 == null ^ s2 == null) {
- return false;
+ @Contract(pure = true)
+ public static boolean isOctalDigit(char c) {
+ return '0' <= c && c <= '7';
}
- if (s1 == null) {
- return true;
+ @NotNull
+ @Contract(pure = true)
+ public static String shortenTextWithEllipsis(@NotNull final String text, final int maxLength, final int suffixLength) {
+ return shortenTextWithEllipsis(text, maxLength, suffixLength, false);
}
- if (s1.length() != s2.length()) {
- return false;
+ @NotNull
+ @Contract(pure = true)
+ public static String trimMiddle(@NotNull String text, int maxLength) {
+ return shortenTextWithEllipsis(text, maxLength, maxLength >> 1, true);
}
- for (int i = 0; i < s1.length(); i++) {
- if (!charsEqualIgnoreCase(s1.charAt(i), s2.charAt(i))) {
- return false;
- }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String shortenTextWithEllipsis(@NotNull final String text,
+ final int maxLength,
+ final int suffixLength,
+ @NotNull String symbol) {
+ final int textLength = text.length();
+ if (textLength > maxLength) {
+ final int prefixLength = maxLength - suffixLength - symbol.length();
+ assert prefixLength > 0;
+ return text.substring(0, prefixLength) + symbol + text.substring(textLength - suffixLength);
+ }
+ else {
+ return text;
+ }
}
- return true;
- }
- @Contract(pure = true)
- public static boolean equalsIgnoreWhitespaces(@Nullable CharSequence s1, @Nullable CharSequence s2) {
- if (s1 == null ^ s2 == null) {
- return false;
+ @NotNull
+ @Contract(pure = true)
+ public static String shortenTextWithEllipsis(@NotNull final String text,
+ final int maxLength,
+ final int suffixLength,
+ boolean useEllipsisSymbol) {
+ String symbol = useEllipsisSymbol ? "\u2026" : "...";
+ return shortenTextWithEllipsis(text, maxLength, suffixLength, symbol);
}
- if (s1 == null) {
- return true;
+ @NotNull
+ @Contract(pure = true)
+ public static String shortenPathWithEllipsis(@NotNull final String path, final int maxLength, boolean useEllipsisSymbol) {
+ return shortenTextWithEllipsis(path, maxLength, (int)(maxLength * 0.7), useEllipsisSymbol);
}
- int len1 = s1.length();
- int len2 = s2.length();
+ @NotNull
+ @Contract(pure = true)
+ public static String shortenPathWithEllipsis(@NotNull final String path, final int maxLength) {
+ return shortenPathWithEllipsis(path, maxLength, false);
+ }
- int index1 = 0;
- int index2 = 0;
- while (index1 < len1 && index2 < len2) {
- if (s1.charAt(index1) == s2.charAt(index2)) {
- index1++;
- index2++;
- continue;
- }
+ @Contract(pure = true)
+ public static boolean charsEqualIgnoreCase(char a, char b) {
+ return charsMatch(a, b, true);
+ }
- boolean skipped = false;
- while (index1 != len1 && isWhiteSpace(s1.charAt(index1))) {
- skipped = true;
- index1++;
- }
- while (index2 != len2 && isWhiteSpace(s2.charAt(index2))) {
- skipped = true;
- index2++;
- }
-
- if (!skipped) return false;
- }
-
- for (; index1 != len1; index1++) {
- if (!isWhiteSpace(s1.charAt(index1))) return false;
- }
- for (; index2 != len2; index2++) {
- if (!isWhiteSpace(s2.charAt(index2))) return false;
- }
-
- return true;
- }
-
- @Contract(pure = true)
- public static boolean equalsTrimWhitespaces(@NotNull CharSequence s1, @NotNull CharSequence s2) {
- int start1 = 0;
- int end1 = s1.length();
- int end2 = s2.length();
-
- while (start1 < end1) {
- char c = s1.charAt(start1);
- if (!isWhiteSpace(c)) break;
- start1++;
- }
-
- while (start1 < end1) {
- char c = s1.charAt(end1 - 1);
- if (!isWhiteSpace(c)) break;
- end1--;
- }
-
- int start2 = 0;
- while (start2 < end2) {
- char c = s2.charAt(start2);
- if (!isWhiteSpace(c)) break;
- start2++;
- }
-
- while (start2 < end2) {
- char c = s2.charAt(end2 - 1);
- if (!isWhiteSpace(c)) break;
- end2--;
- }
-
- CharSequence ts1 = new CharSequenceSubSequence(s1, start1, end1);
- CharSequence ts2 = new CharSequenceSubSequence(s2, start2, end2);
-
- return equals(ts1, ts2);
- }
-
- /**
- * Collapses all white-space (including new lines) between non-white-space characters to a single space character.
- * Leading and trailing white space is removed.
- */
- public static String collapseWhiteSpace(@NotNull CharSequence s) {
- final StringBuilder result = new StringBuilder();
- boolean space = false;
- for (int i = 0, length = s.length(); i < length; i++) {
- final char ch = s.charAt(i);
- if (isWhiteSpace(ch)) {
- if (!space) space = true;
- }
- else {
- if (space && result.length() > 0) result.append(' ');
- result.append(ch);
- space = false;
- }
- }
- return result.toString();
- }
-
- @Contract(pure = true)
- public static boolean findIgnoreCase(@Nullable String toFind, @NotNull String... where) {
- for (String string : where) {
- if (equalsIgnoreCase(toFind, string)) return true;
- }
- return false;
- }
-
- @Contract(pure = true)
- public static int compare(char c1, char c2, boolean ignoreCase) {
- // duplicating String.equalsIgnoreCase logic
- int d = c1 - c2;
- if (d == 0 || !ignoreCase) {
- return d;
- }
- // If characters don't match but case may be ignored,
- // try converting both characters to uppercase.
- // If the results match, then the comparison scan should
- // continue.
- char u1 = StringUtilRt.toUpperCase(c1);
- char u2 = StringUtilRt.toUpperCase(c2);
- d = u1 - u2;
- if (d != 0) {
- // Unfortunately, conversion to uppercase does not work properly
- // for the Georgian alphabet, which has strange rules about case
- // conversion. So we need to make one last check before
- // exiting.
- d = StringUtilRt.toLowerCase(u1) - StringUtilRt.toLowerCase(u2);
- }
- return d;
- }
-
- @Contract(pure = true)
- public static boolean charsMatch(char c1, char c2, boolean ignoreCase) {
- return compare(c1, c2, ignoreCase) == 0;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String formatLinks(@NotNull String message) {
- Pattern linkPattern = Pattern.compile("http://[a-zA-Z0-9./\\-+]+");
- StringBuffer result = new StringBuffer();
- Matcher m = linkPattern.matcher(message);
- while (m.find()) {
- m.appendReplacement(result, "" + m.group() + "");
- }
- m.appendTail(result);
- return result.toString();
- }
-
- @Contract(pure = true)
- public static boolean isHexDigit(char c) {
- return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F';
- }
-
- @Contract(pure = true)
- public static boolean isOctalDigit(char c) {
- return '0' <= c && c <= '7';
- }
-
- @NotNull
- @Contract(pure = true)
- public static String shortenTextWithEllipsis(@NotNull final String text, final int maxLength, final int suffixLength) {
- return shortenTextWithEllipsis(text, maxLength, suffixLength, false);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String trimMiddle(@NotNull String text, int maxLength) {
- return shortenTextWithEllipsis(text, maxLength, maxLength >> 1, true);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String shortenTextWithEllipsis(@NotNull final String text,
- final int maxLength,
- final int suffixLength,
- @NotNull String symbol) {
- final int textLength = text.length();
- if (textLength > maxLength) {
- final int prefixLength = maxLength - suffixLength - symbol.length();
- assert prefixLength > 0;
- return text.substring(0, prefixLength) + symbol + text.substring(textLength - suffixLength);
- }
- else {
- return text;
- }
- }
-
- @NotNull
- @Contract(pure = true)
- public static String shortenTextWithEllipsis(@NotNull final String text,
- final int maxLength,
- final int suffixLength,
- boolean useEllipsisSymbol) {
- String symbol = useEllipsisSymbol ? "\u2026" : "...";
- return shortenTextWithEllipsis(text, maxLength, suffixLength, symbol);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String shortenPathWithEllipsis(@NotNull final String path, final int maxLength, boolean useEllipsisSymbol) {
- return shortenTextWithEllipsis(path, maxLength, (int)(maxLength * 0.7), useEllipsisSymbol);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String shortenPathWithEllipsis(@NotNull final String path, final int maxLength) {
- return shortenPathWithEllipsis(path, maxLength, false);
- }
-
- @Contract(pure = true)
- public static boolean charsEqualIgnoreCase(char a, char b) {
- return charsMatch(a, b, true);
- }
-
- @Contract(pure = true)
- public static char toUpperCase(char a) {
- return StringUtilRt.toUpperCase(a);
- }
+ @Contract(pure = true)
+ public static char toUpperCase(char a) {
+ return StringUtilRt.toUpperCase(a);
+ }
@Contract(value = "null -> null; !null -> !null", pure = true)
public static String toUpperCase(String a) {
if (a == null)
return null;
-
+
StringBuilder answer = null;
for (int i = 0; i < a.length(); i++) {
char c = a.charAt(i);
@@ -3050,300 +3055,300 @@ public static String toUpperCase(String a) {
}
}
return answer == null ? a : answer.toString();
- }
-
- @Contract(pure = true)
- public static char toLowerCase(final char a) {
- return StringUtilRt.toLowerCase(a);
- }
-
- @Contract(pure = true)
- public static boolean isUpperCase(@NotNull CharSequence sequence) {
- for (int i = 0; i < sequence.length(); i++) {
- if (!Character.isUpperCase(sequence.charAt(i))) return false;
- }
- return true;
- }
-
- @Nullable
- public static LineSeparator detectSeparators(@NotNull CharSequence text) {
- int index = indexOfAny(text, "\n\r");
- if (index == -1) return null;
- LineSeparator lineSeparator = getLineSeparatorAt(text, index);
- if (lineSeparator == null) {
- throw new AssertionError();
- }
- return lineSeparator;
- }
-
- @Nullable
- public static LineSeparator getLineSeparatorAt(@NotNull CharSequence text, int index) {
- if (index < 0 || index >= text.length()) {
- return null;
- }
- char ch = text.charAt(index);
- if (ch == '\r') {
- return index + 1 < text.length() && text.charAt(index + 1) == '\n' ? LineSeparator.CRLF : LineSeparator.CR;
- }
- return ch == '\n' ? LineSeparator.LF : null;
- }
-
- @NotNull
- @Contract(pure = true)
- public static String convertLineSeparators(@NotNull String text) {
- return StringUtilRt.convertLineSeparators(text);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String convertLineSeparators(@NotNull String text, boolean keepCarriageReturn) {
- return StringUtilRt.convertLineSeparators(text, keepCarriageReturn);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator) {
- return StringUtilRt.convertLineSeparators(text, newSeparator);
- }
-
- @NotNull
- public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator, @Nullable int[] offsetsToKeep) {
- return StringUtilRt.convertLineSeparators(text, newSeparator, offsetsToKeep);
- }
-
- @Contract(pure = true)
- public static int parseInt(@Nullable String string, int defaultValue) {
- return StringUtilRt.parseInt(string, defaultValue);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String getShortName(@NotNull String fqName) {
- return StringUtilRt.getShortName(fqName);
- }
-
- @NotNull
- @Contract(pure = true)
- public static String getShortName(@NotNull String fqName, char separator) {
- return StringUtilRt.getShortName(fqName, separator);
- }
-
- /**
- * Equivalent for {@code getShortName(fqName).equals(shortName)}, but could be faster.
- *
- * @param fqName fully-qualified name (dot-separated)
- * @param shortName a short name, must not contain dots
- * @return true if specified short name is a short name of fully-qualified name
- */
- public static boolean isShortNameOf(@NotNull String fqName, @NotNull String shortName) {
- if (fqName.length() < shortName.length()) return false;
- if (fqName.length() == shortName.length()) return fqName.equals(shortName);
- int diff = fqName.length() - shortName.length();
- if (fqName.charAt(diff - 1) != '.') return false;
- return fqName.regionMatches(diff, shortName, 0, shortName.length());
- }
-
- /**
- * Strips class name from Object#toString if present.
- * To be used as custom data type renderer for java.lang.Object.
- * To activate just add {@code StringUtil.toShortString(this)}
- * expression in Settings | Debugger | Data Views.
- */
- @Contract("null->null;!null->!null")
- @SuppressWarnings("UnusedDeclaration")
- static String toShortString(@Nullable Object o) {
- if (o == null) return null;
- if (o instanceof CharSequence) return o.toString();
- String className = o.getClass().getName();
- String s = o.toString();
- if (!s.startsWith(className)) return s;
- return s.length() > className.length() && !Character.isLetter(s.charAt(className.length())) ?
- trimStart(s, className) : s;
- }
-
- @NotNull
- @Contract(pure = true)
- public static CharSequence newBombedCharSequence(@NotNull CharSequence sequence, long delay) {
- final long myTime = System.currentTimeMillis() + delay;
- return new BombedCharSequence(sequence) {
- @Override
- protected void checkCanceled() {
- long l = System.currentTimeMillis();
- if (l >= myTime) {
- throw new ProcessCanceledException();
- }
- }
- };
- }
-
- public static boolean trimEnd(@NotNull StringBuilder buffer, @NotNull CharSequence end) {
- if (endsWith(buffer, end)) {
- buffer.delete(buffer.length() - end.length(), buffer.length());
- return true;
- }
- return false;
- }
-
- /**
- * Say smallPart = "op" and bigPart="open". Method returns true for "Ope" and false for "ops"
- */
- @Contract(pure = true)
- @SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale")
- public static boolean isBetween(@NotNull String string, @NotNull String smallPart, @NotNull String bigPart) {
- final String s = string.toLowerCase();
- return s.startsWith(smallPart.toLowerCase()) && bigPart.toLowerCase().startsWith(s);
- }
-
- /**
- * Does the string have an uppercase character?
- * @param s the string to test.
- * @return true if the string has an uppercase character, false if not.
- */
- public static boolean hasUpperCaseChar(String s) {
- char[] chars = s.toCharArray();
- for (char c : chars) {
- if (Character.isUpperCase(c)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Does the string have a lowercase character?
- * @param s the string to test.
- * @return true if the string has a lowercase character, false if not.
- */
- public static boolean hasLowerCaseChar(String s) {
- char[] chars = s.toCharArray();
- for (char c : chars) {
- if (Character.isLowerCase(c)) {
- return true;
- }
- }
- return false;
- }
-
- private static final Pattern UNICODE_CHAR = Pattern.compile("\\\\u[0-9a-fA-F]{4}");
-
- public static String replaceUnicodeEscapeSequences(String text) {
- if (text == null) return null;
-
- final Matcher matcher = UNICODE_CHAR.matcher(text);
- if (!matcher.find()) return text; // fast path
-
- matcher.reset();
- int lastEnd = 0;
- final StringBuilder sb = new StringBuilder(text.length());
- while (matcher.find()) {
- sb.append(text, lastEnd, matcher.start());
- final char c = (char)Integer.parseInt(matcher.group().substring(2), 16);
- sb.append(c);
- lastEnd = matcher.end();
- }
- sb.append(text.substring(lastEnd));
- return sb.toString();
- }
-
- /**
- * Expirable CharSequence. Very useful to control external library execution time,
- * i.e. when java.util.regex.Pattern match goes out of control.
- */
- public abstract static class BombedCharSequence implements CharSequence {
- private final CharSequence delegate;
- private int i;
- private boolean myDefused;
-
- public BombedCharSequence(@NotNull CharSequence sequence) {
- delegate = sequence;
- }
-
- @Override
- public int length() {
- check();
- return delegate.length();
- }
-
- @Override
- public char charAt(int i) {
- check();
- return delegate.charAt(i);
- }
-
- protected void check() {
- if (myDefused) {
- return;
- }
- if ((++i & 1023) == 0) {
- checkCanceled();
- }
- }
-
- public final void defuse() {
- myDefused = true;
- }
-
- @NotNull
- @Override
- public String toString() {
- check();
- return delegate.toString();
- }
-
- protected abstract void checkCanceled();
-
- @NotNull
- @Override
- public CharSequence subSequence(int i, int i1) {
- check();
- return delegate.subSequence(i, i1);
- }
- }
-
- @Contract(pure = true)
- @NotNull
- public static String toHexString(@NotNull byte[] bytes) {
- @SuppressWarnings("SpellCheckingInspection") String digits = "0123456789abcdef";
- StringBuilder sb = new StringBuilder(2 * bytes.length);
- for (byte b : bytes) sb.append(digits.charAt((b >> 4) & 0xf)).append(digits.charAt(b & 0xf));
- return sb.toString();
- }
-
- @Contract(pure = true)
- @NotNull
- public static byte[] parseHexString(@NotNull String str) {
- int len = str.length();
- if (len % 2 != 0) throw new IllegalArgumentException("Non-even-length: " + str);
- byte[] bytes = new byte[len / 2];
- for (int i = 0; i < len; i += 2) {
- bytes[i / 2] = (byte)((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
- }
- return bytes;
- }
-
- /** @deprecated use {@link #startsWithConcatenation(String, String...)} (to remove in IDEA 15) */
- @Deprecated
- public static boolean startsWithConcatenationOf(@NotNull String string, @NotNull String firstPrefix, @NotNull String secondPrefix) {
- return startsWithConcatenation(string, firstPrefix, secondPrefix);
- }
-
- /**
- * @return {@code true} if the passed string is not {@code null} and not empty
- * and contains only latin upper- or lower-case characters and digits; {@code false} otherwise.
- */
- @Contract(pure = true)
- public static boolean isLatinAlphanumeric(@Nullable CharSequence str) {
- if (isEmpty(str)) {
- return false;
- }
- for (int i = 0; i < str.length(); i++) {
- char c = str.charAt(i);
- if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || Character.isDigit(c)) {
- continue;
- }
- return false;
- }
- return true;
- }
-
+ }
+
+ @Contract(pure = true)
+ public static char toLowerCase(final char a) {
+ return StringUtilRt.toLowerCase(a);
+ }
+
+ @Contract(pure = true)
+ public static boolean isUpperCase(@NotNull CharSequence sequence) {
+ for (int i = 0; i < sequence.length(); i++) {
+ if (!Character.isUpperCase(sequence.charAt(i))) return false;
+ }
+ return true;
+ }
+
+ @Nullable
+ public static LineSeparator detectSeparators(@NotNull CharSequence text) {
+ int index = indexOfAny(text, "\n\r");
+ if (index == -1) return null;
+ LineSeparator lineSeparator = getLineSeparatorAt(text, index);
+ if (lineSeparator == null) {
+ throw new AssertionError();
+ }
+ return lineSeparator;
+ }
+
+ @Nullable
+ public static LineSeparator getLineSeparatorAt(@NotNull CharSequence text, int index) {
+ if (index < 0 || index >= text.length()) {
+ return null;
+ }
+ char ch = text.charAt(index);
+ if (ch == '\r') {
+ return index + 1 < text.length() && text.charAt(index + 1) == '\n' ? LineSeparator.CRLF : LineSeparator.CR;
+ }
+ return ch == '\n' ? LineSeparator.LF : null;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String convertLineSeparators(@NotNull String text) {
+ return StringUtilRt.convertLineSeparators(text);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String convertLineSeparators(@NotNull String text, boolean keepCarriageReturn) {
+ return StringUtilRt.convertLineSeparators(text, keepCarriageReturn);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator) {
+ return StringUtilRt.convertLineSeparators(text, newSeparator);
+ }
+
+ @NotNull
+ public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator, @Nullable int[] offsetsToKeep) {
+ return StringUtilRt.convertLineSeparators(text, newSeparator, offsetsToKeep);
+ }
+
+ @Contract(pure = true)
+ public static int parseInt(@Nullable String string, int defaultValue) {
+ return StringUtilRt.parseInt(string, defaultValue);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String getShortName(@NotNull String fqName) {
+ return StringUtilRt.getShortName(fqName);
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static String getShortName(@NotNull String fqName, char separator) {
+ return StringUtilRt.getShortName(fqName, separator);
+ }
+
+ /**
+ * Equivalent for {@code getShortName(fqName).equals(shortName)}, but could be faster.
+ *
+ * @param fqName fully-qualified name (dot-separated)
+ * @param shortName a short name, must not contain dots
+ * @return true if specified short name is a short name of fully-qualified name
+ */
+ public static boolean isShortNameOf(@NotNull String fqName, @NotNull String shortName) {
+ if (fqName.length() < shortName.length()) return false;
+ if (fqName.length() == shortName.length()) return fqName.equals(shortName);
+ int diff = fqName.length() - shortName.length();
+ if (fqName.charAt(diff - 1) != '.') return false;
+ return fqName.regionMatches(diff, shortName, 0, shortName.length());
+ }
+
+ /**
+ * Strips class name from Object#toString if present.
+ * To be used as custom data type renderer for java.lang.Object.
+ * To activate just add {@code StringUtil.toShortString(this)}
+ * expression in Settings | Debugger | Data Views.
+ */
+ @Contract("null->null;!null->!null")
+ @SuppressWarnings("UnusedDeclaration")
+ static String toShortString(@Nullable Object o) {
+ if (o == null) return null;
+ if (o instanceof CharSequence) return o.toString();
+ String className = o.getClass().getName();
+ String s = o.toString();
+ if (!s.startsWith(className)) return s;
+ return s.length() > className.length() && !Character.isLetter(s.charAt(className.length())) ?
+ trimStart(s, className) : s;
+ }
+
+ @NotNull
+ @Contract(pure = true)
+ public static CharSequence newBombedCharSequence(@NotNull CharSequence sequence, long delay) {
+ final long myTime = System.currentTimeMillis() + delay;
+ return new BombedCharSequence(sequence) {
+ @Override
+ protected void checkCanceled() {
+ long l = System.currentTimeMillis();
+ if (l >= myTime) {
+ throw new ProcessCanceledException();
+ }
+ }
+ };
+ }
+
+ public static boolean trimEnd(@NotNull StringBuilder buffer, @NotNull CharSequence end) {
+ if (endsWith(buffer, end)) {
+ buffer.delete(buffer.length() - end.length(), buffer.length());
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Say smallPart = "op" and bigPart="open". Method returns true for "Ope" and false for "ops"
+ */
+ @Contract(pure = true)
+ @SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale")
+ public static boolean isBetween(@NotNull String string, @NotNull String smallPart, @NotNull String bigPart) {
+ final String s = string.toLowerCase();
+ return s.startsWith(smallPart.toLowerCase()) && bigPart.toLowerCase().startsWith(s);
+ }
+
+ /**
+ * Does the string have an uppercase character?
+ * @param s the string to test.
+ * @return true if the string has an uppercase character, false if not.
+ */
+ public static boolean hasUpperCaseChar(String s) {
+ char[] chars = s.toCharArray();
+ for (char c : chars) {
+ if (Character.isUpperCase(c)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Does the string have a lowercase character?
+ * @param s the string to test.
+ * @return true if the string has a lowercase character, false if not.
+ */
+ public static boolean hasLowerCaseChar(String s) {
+ char[] chars = s.toCharArray();
+ for (char c : chars) {
+ if (Character.isLowerCase(c)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static final Pattern UNICODE_CHAR = Pattern.compile("\\\\u[0-9a-fA-F]{4}");
+
+ public static String replaceUnicodeEscapeSequences(String text) {
+ if (text == null) return null;
+
+ final Matcher matcher = UNICODE_CHAR.matcher(text);
+ if (!matcher.find()) return text; // fast path
+
+ matcher.reset();
+ int lastEnd = 0;
+ final StringBuilder sb = new StringBuilder(text.length());
+ while (matcher.find()) {
+ sb.append(text, lastEnd, matcher.start());
+ final char c = (char)Integer.parseInt(matcher.group().substring(2), 16);
+ sb.append(c);
+ lastEnd = matcher.end();
+ }
+ sb.append(text.substring(lastEnd));
+ return sb.toString();
+ }
+
+ /**
+ * Expirable CharSequence. Very useful to control external library execution time,
+ * i.e. when java.util.regex.Pattern match goes out of control.
+ */
+ public abstract static class BombedCharSequence implements CharSequence {
+ private final CharSequence delegate;
+ private int i;
+ private boolean myDefused;
+
+ public BombedCharSequence(@NotNull CharSequence sequence) {
+ delegate = sequence;
+ }
+
+ @Override
+ public int length() {
+ check();
+ return delegate.length();
+ }
+
+ @Override
+ public char charAt(int i) {
+ check();
+ return delegate.charAt(i);
+ }
+
+ protected void check() {
+ if (myDefused) {
+ return;
+ }
+ if ((++i & 1023) == 0) {
+ checkCanceled();
+ }
+ }
+
+ public final void defuse() {
+ myDefused = true;
+ }
+
+ @NotNull
+ @Override
+ public String toString() {
+ check();
+ return delegate.toString();
+ }
+
+ protected abstract void checkCanceled();
+
+ @NotNull
+ @Override
+ public CharSequence subSequence(int i, int i1) {
+ check();
+ return delegate.subSequence(i, i1);
+ }
+ }
+
+ @Contract(pure = true)
+ @NotNull
+ public static String toHexString(@NotNull byte[] bytes) {
+ @SuppressWarnings("SpellCheckingInspection") String digits = "0123456789abcdef";
+ StringBuilder sb = new StringBuilder(2 * bytes.length);
+ for (byte b : bytes) sb.append(digits.charAt((b >> 4) & 0xf)).append(digits.charAt(b & 0xf));
+ return sb.toString();
+ }
+
+ @Contract(pure = true)
+ @NotNull
+ public static byte[] parseHexString(@NotNull String str) {
+ int len = str.length();
+ if (len % 2 != 0) throw new IllegalArgumentException("Non-even-length: " + str);
+ byte[] bytes = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ bytes[i / 2] = (byte)((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
+ }
+ return bytes;
+ }
+
+ /** @deprecated use {@link #startsWithConcatenation(String, String...)} (to remove in IDEA 15) */
+ @Deprecated
+ public static boolean startsWithConcatenationOf(@NotNull String string, @NotNull String firstPrefix, @NotNull String secondPrefix) {
+ return startsWithConcatenation(string, firstPrefix, secondPrefix);
+ }
+
+ /**
+ * @return {@code true} if the passed string is not {@code null} and not empty
+ * and contains only latin upper- or lower-case characters and digits; {@code false} otherwise.
+ */
+ @Contract(pure = true)
+ public static boolean isLatinAlphanumeric(@Nullable CharSequence str) {
+ if (isEmpty(str)) {
+ return false;
+ }
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || Character.isDigit(c)) {
+ continue;
+ }
+ return false;
+ }
+ return true;
+ }
+
}
\ No newline at end of file
diff --git a/kotlin-bundled-compiler/src/com/intellij/util/ObjectUtils.java b/kotlin-bundled-compiler/src/com/intellij/util/ObjectUtils.java
deleted file mode 100644
index 1ba3d7102..000000000
--- a/kotlin-bundled-compiler/src/com/intellij/util/ObjectUtils.java
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
-package com.intellij.util;
-
-import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.NotNullFactory;
-import com.intellij.util.containers.Convertor;
-import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.lang.reflect.Proxy;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * @author peter
- */
-public final class ObjectUtils {
- private ObjectUtils() {
- }
-
- /**
- * @see NotNullizer
- */
- public static final Object NULL = sentinel("ObjectUtils.NULL");
-
- /**
- * Creates a new object which could be used as sentinel value (special value to distinguish from any other object). It does not equal
- * to any other object. Usually should be assigned to the static final field.
- *
- * @param name an object name, returned from {@link #toString()} to simplify the debugging or heap dump analysis
- * (guaranteed to be stored as sentinel object field). If sentinel is assigned to the static final field,
- * it's recommended to supply that field name (possibly qualified with the class name).
- * @return a new sentinel object
- */
- @NotNull
- public static Object sentinel(@NotNull @NonNls String name) {
- return new Sentinel(name);
- }
-
- /**
- * They promise in http://mail.openjdk.java.net/pipermail/core-libs-dev/2018-February/051312.html that
- * the object reference won't be removed by JIT and GC-ed until this call.
- */
- public static void reachabilityFence(@SuppressWarnings("unused") Object o) {}
-
- private static final class Sentinel {
- private final String myName;
-
- Sentinel(@NotNull String name) {
- myName = name;
- }
-
- @Override
- public String toString() {
- return myName;
- }
- }
-
- /**
- * Creates an instance of class {@code ofInterface} with its {@link Object#toString()} method returning {@code name}.
- * No other guarantees about return value behaviour.
- * {@code ofInterface} must represent an interface class.
- * Useful for stubs in generic code, e.g. for storing in {@code List} to represent empty special value.
- */
- @NotNull
- public static T sentinel(@NotNull final String name, @NotNull Class ofInterface) {
- if (!ofInterface.isInterface()) {
- throw new IllegalArgumentException("Expected interface but got: " + ofInterface);
- }
- // java.lang.reflect.Proxy.ProxyClassFactory fails if the class is not available via the classloader.
- // We must use interface own classloader because classes from plugins are not available via ObjectUtils' classloader.
- //noinspection unchecked
- return (T)Proxy.newProxyInstance(ofInterface.getClassLoader(), new Class[]{ofInterface}, (__, method, args) -> {
- if ("toString".equals(method.getName()) && args.length == 0) {
- return name;
- }
- throw new AbstractMethodError();
- });
- }
-
- /**
- * @deprecated Use {@link Objects#requireNonNull(Object)}
- */
- @Deprecated
- public static @NotNull T assertNotNull(@Nullable T t) {
- return Objects.requireNonNull(t);
- }
-
- public static void assertAllElementsNotNull(T [] array) {
- for (int i = 0; i < array.length; i++) {
- T t = array[i];
- if (t == null) {
- throw new NullPointerException("Element [" + i + "] is null");
- }
- }
- }
-
- @Contract(value = "!null, _ -> !null; _, !null -> !null; null, null -> null", pure = true)
- public static T chooseNotNull(@Nullable T t1, @Nullable T t2) {
- return t1 == null? t2 : t1;
- }
-
- @Contract(value = "!null, _ -> !null; _, !null -> !null; null, null -> null", pure = true)
- public static T coalesce(@Nullable T t1, @Nullable T t2) {
- return chooseNotNull(t1, t2);
- }
-
- @Contract(value = "!null, _, _ -> !null; _, !null, _ -> !null; _, _, !null -> !null; null,null,null -> null", pure = true)
- public static T coalesce(@Nullable T t1, @Nullable T t2, @Nullable T t3) {
- return t1 != null ? t1 : t2 != null ? t2 : t3;
- }
-
- @Nullable
- public static T coalesce(@Nullable Iterable extends T> o) {
- if (o == null) return null;
- for (T t : o) {
- if (t != null) return t;
- }
- return null;
- }
-
- /**
- * @deprecated Use {@link Objects#requireNonNull(Object)}
- */
- @Deprecated
- public static T notNull(@Nullable T value) {
- return Objects.requireNonNull(value);
- }
-
- @NotNull
- @Contract(pure = true)
- public static T notNull(@Nullable T value, @NotNull T defaultValue) {
- return value == null ? defaultValue : value;
- }
-
- @NotNull
- public static T notNull(@Nullable T value, @NotNull NotNullFactory extends T> defaultValue) {
- return value == null ? defaultValue.create() : value;
- }
-
- @Contract(value = "null, _ -> null", pure = true)
- @Nullable
- public static T tryCast(@Nullable Object obj, @NotNull Class clazz) {
- if (clazz.isInstance(obj)) {
- return clazz.cast(obj);
- }
- return null;
- }
-
- @Nullable
- public static S doIfCast(@Nullable Object obj, @NotNull Class clazz, final Convertor super T, ? extends S> convertor) {
- if (clazz.isInstance(obj)) {
- //noinspection unchecked
- return convertor.convert((T)obj);
- }
- return null;
- }
-
- @Contract("null, _ -> null")
- @Nullable
- public static S doIfNotNull(@Nullable T obj, @NotNull Function super T, ? extends S> function) {
- return obj == null ? null : function.fun(obj);
- }
-
- public static void consumeIfNotNull(@Nullable T obj, @NotNull Consumer super T> consumer) {
- if (obj != null) {
- consumer.consume(obj);
- }
- }
-
- public static void consumeIfCast(@Nullable Object obj, @NotNull Class clazz, final Consumer super T> consumer) {
- if (clazz.isInstance(obj)) {
- //noinspection unchecked
- consumer.consume((T)obj);
- }
- }
-
- @Nullable
- @Contract("null, _ -> null")
- public static T nullizeByCondition(@Nullable final T obj, @NotNull final Condition super T> condition) {
- if (condition.value(obj)) {
- return null;
- }
- return obj;
- }
-
- @Nullable
- @Contract("null, _ -> null")
- public static T nullizeIfDefaultValue(@Nullable T obj, @NotNull T defaultValue) {
- if (obj == defaultValue) {
- return null;
- }
- return obj;
- }
-
- /**
- * Performs binary search on the range [fromIndex, toIndex)
- * @param indexComparator a comparator which receives a middle index and returns the result of comparision of the value at this index and the goal value
- * (e.g 0 if found, -1 if the value[middleIndex] < goal, or 1 if value[middleIndex] > goal)
- * @return index for which {@code indexComparator} returned 0 or {@code -insertionIndex-1} if wasn't found
- * @see java.util.Arrays#binarySearch(Object[], Object, Comparator)
- * @see java.util.Collections#binarySearch(List, Object, Comparator)
- */
- public static int binarySearch(int fromIndex, int toIndex, @NotNull IntIntFunction indexComparator) {
- int low = fromIndex;
- int high = toIndex - 1;
- while (low <= high) {
- int mid = (low + high) >>> 1;
- int cmp = indexComparator.fun(mid);
- if (cmp < 0) low = mid + 1;
- else if (cmp > 0) high = mid - 1;
- else return mid;
- }
- return -(low + 1);
- }
-}
diff --git a/kotlin-bundled-compiler/src/com/intellij/util/containers/ContainerUtil.java b/kotlin-bundled-compiler/src/com/intellij/util/containers/ContainerUtil.java
deleted file mode 100644
index 01a7e69b3..000000000
--- a/kotlin-bundled-compiler/src/com/intellij/util/containers/ContainerUtil.java
+++ /dev/null
@@ -1,3014 +0,0 @@
-// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
-package com.intellij.util.containers;
-
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.util.*;
-import com.intellij.util.*;
-import gnu.trove.*;
-import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.lang.reflect.Array;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-@SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass"})
-public class ContainerUtil extends ContainerUtilRt {
- private static final int INSERTION_SORT_THRESHOLD = 10;
-
- @NotNull
- @Contract(pure=true)
- public static T[] ar(@NotNull T... elements) {
- return elements;
- }
-
- @NotNull
- @Contract(pure=true)
- public static HashMap newHashMap() {
- return ContainerUtilRt.newHashMap();
- }
-
- @NotNull
- @Contract(pure=true)
- public static HashMap newHashMap(@NotNull Map extends K, ? extends V> map) {
- return ContainerUtilRt.newHashMap(map);
- }
-
- @NotNull
- @Contract(pure=true)
- public static Map newHashMap(@NotNull Pair extends K, ? extends V> first, @NotNull Pair extends K, ? extends V>... entries) {
- return ContainerUtilRt.newHashMap(first, entries);
- }
-
- @NotNull
- @Contract(pure=true)
- public static Map newHashMap(@NotNull List extends K> keys, @NotNull List extends V> values) {
- return ContainerUtilRt.newHashMap(keys, values);
- }
-
- @NotNull
- @Contract(pure=true)
- public static TreeMap newTreeMap() {
- return ContainerUtilRt.newTreeMap();
- }
-
- @NotNull
- @Contract(pure=true)
- public static TreeMap newTreeMap(@NotNull Map extends K, ? extends V> map) {
- return ContainerUtilRt.newTreeMap(map);
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedHashMap newLinkedHashMap() {
- return ContainerUtilRt.newLinkedHashMap();
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedHashMap newLinkedHashMap(int capacity) {
- return ContainerUtilRt.newLinkedHashMap(capacity);
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedHashMap newLinkedHashMap(@NotNull Map extends K, ? extends V> map) {
- return ContainerUtilRt.newLinkedHashMap(map);
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedHashMap newLinkedHashMap(@NotNull Pair extends K, ? extends V> first, @NotNull Pair extends K, ? extends V>... entries) {
- return ContainerUtilRt.newLinkedHashMap(first, entries);
- }
-
- @NotNull
- @Contract(pure=true)
- public static THashMap newTroveMap() {
- return new THashMap();
- }
-
- @NotNull
- @Contract(pure=true)
- public static THashMap newTroveMap(@NotNull TObjectHashingStrategy strategy) {
- return new THashMap(strategy);
- }
-
- @NotNull
- @Contract(pure=true)
- public static , V> EnumMap newEnumMap(@NotNull Class keyType) {
- return new EnumMap(keyType);
- }
-
- @SuppressWarnings("unchecked")
- @NotNull
- @Contract(pure=true)
- public static TObjectHashingStrategy canonicalStrategy() {
- return TObjectHashingStrategy.CANONICAL;
- }
-
- @SuppressWarnings("unchecked")
- @NotNull
- @Contract(pure=true)
- public static TObjectHashingStrategy identityStrategy() {
- return TObjectHashingStrategy.IDENTITY;
- }
-
- @NotNull
- @Contract(pure=true)
- public static IdentityHashMap newIdentityHashMap() {
- return new IdentityHashMap();
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedList newLinkedList() {
- return ContainerUtilRt.newLinkedList();
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedList newLinkedList(@NotNull T... elements) {
- return ContainerUtilRt.newLinkedList(elements);
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedList newLinkedList(@NotNull Iterable extends T> elements) {
- return ContainerUtilRt.newLinkedList(elements);
- }
-
- @NotNull
- @Contract(pure=true)
- public static ArrayList newArrayList() {
- return ContainerUtilRt.newArrayList();
- }
-
- @NotNull
- @Contract(pure=true)
- public static ArrayList newArrayList(@NotNull E... array) {
- return ContainerUtilRt.newArrayList(array);
- }
-
- @NotNull
- @Contract(pure=true)
- public static ArrayList newArrayList(@NotNull Iterable extends E> iterable) {
- return ContainerUtilRt.newArrayList(iterable);
- }
-
- @NotNull
- @Contract(pure=true)
- public static ArrayList newArrayListWithCapacity(int size) {
- return ContainerUtilRt.newArrayListWithCapacity(size);
- }
-
- @NotNull
- @Contract(pure=true)
- public static List newArrayList(@NotNull final T[] elements, final int start, final int end) {
- if (start < 0 || start > end || end > elements.length) {
- throw new IllegalArgumentException("start:" + start + " end:" + end + " length:" + elements.length);
- }
-
- return new AbstractList() {
- private final int size = end - start;
-
- @Override
- public T get(final int index) {
- if (index < 0 || index >= size) throw new IndexOutOfBoundsException("index:" + index + " size:" + size);
- return elements[start + index];
- }
-
- @Override
- public int size() {
- return size;
- }
- };
- }
-
- @NotNull
- @Contract(pure = true)
- public static List newUnmodifiableList(List extends T> originalList) {
- int size = originalList.size();
- if (size == 0) {
- return emptyList();
- }
- else if (size == 1) {
- return Collections.singletonList(originalList.get(0));
- }
- else {
- return Collections.unmodifiableList(newArrayList(originalList));
- }
- }
-
- @NotNull
- @Contract(pure = true)
- public static Collection unmodifiableOrEmptyCollection(@NotNull Collection extends T> original) {
- int size = original.size();
- if (size == 0) {
- return emptyList();
- }
- if (size == 1) {
- return Collections.singletonList(original.iterator().next());
- }
- else {
- return Collections.unmodifiableCollection(original);
- }
- }
-
- @NotNull
- @Contract(pure = true)
- public static List unmodifiableOrEmptyList(@NotNull List extends T> original) {
- int size = original.size();
- if (size == 0) {
- return emptyList();
- }
- if (size == 1) {
- return Collections.singletonList(original.iterator().next());
- }
- else {
- return Collections.unmodifiableList(original);
- }
- }
-
- @NotNull
- @Contract(pure = true)
- public static Set unmodifiableOrEmptySet(@NotNull Set extends T> original) {
- int size = original.size();
- if (size == 0) {
- return Collections.emptySet();
- }
- if (size == 1) {
- return Collections.singleton(original.iterator().next());
- }
- else {
- return Collections.unmodifiableSet(original);
- }
- }
-
- @NotNull
- @Contract(pure = true)
- public static Map unmodifiableOrEmptyMap(@NotNull Map extends K, ? extends V> original) {
- int size = original.size();
- if (size == 0) {
- return Collections.emptyMap();
- }
- if (size == 1) {
- Map.Entry extends K, ? extends V> entry = original.entrySet().iterator().next();
- return Collections.singletonMap(entry.getKey(), entry.getValue());
- }
- else {
- return Collections.unmodifiableMap(original);
- }
- }
-
- @NotNull
- @Contract(pure=true)
- public static List newSmartList() {
- return new SmartList();
- }
-
- @NotNull
- @Contract(pure=true)
- public static List newSmartList(T element) {
- return new SmartList(element);
- }
-
- @NotNull
- @Contract(pure=true)
- public static List newSmartList(@NotNull T... elements) {
- return new SmartList(elements);
- }
-
- @NotNull
- @Contract(pure=true)
- public static HashSet newHashSet() {
- return ContainerUtilRt.newHashSet();
- }
-
- @NotNull
- @Contract(pure=true)
- public static HashSet newHashSet(int initialCapacity) {
- return ContainerUtilRt.newHashSet(initialCapacity);
- }
-
- @NotNull
- @Contract(pure=true)
- public static HashSet newHashSet(@NotNull T... elements) {
- return ContainerUtilRt.newHashSet(elements);
- }
-
- @NotNull
- @Contract(pure=true)
- public static HashSet newHashSet(@NotNull Iterable extends T> iterable) {
- return ContainerUtilRt.newHashSet(iterable);
- }
-
- @NotNull
- public static HashSet newHashSet(@NotNull Iterator extends T> iterator) {
- return ContainerUtilRt.newHashSet(iterator);
- }
-
- @NotNull
- @Contract(pure=true)
- public static Set newHashOrEmptySet(@Nullable Iterable extends T> iterable) {
- boolean empty = iterable == null || iterable instanceof Collection && ((Collection)iterable).isEmpty();
- return empty ? Collections.emptySet() : ContainerUtilRt.newHashSet(iterable);
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedHashSet newLinkedHashSet() {
- return ContainerUtilRt.newLinkedHashSet();
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedHashSet newLinkedHashSet(@NotNull Iterable extends T> elements) {
- return ContainerUtilRt.newLinkedHashSet(elements);
- }
-
- @NotNull
- @Contract(pure=true)
- public static LinkedHashSet newLinkedHashSet(@NotNull T... elements) {
- return ContainerUtilRt.newLinkedHashSet(elements);
- }
-
- @NotNull
- @Contract(pure=true)
- public static THashSet newTroveSet() {
- return new THashSet();
- }
-
- @NotNull
- @Contract(pure=true)
- public static THashSet newTroveSet(@NotNull TObjectHashingStrategy strategy) {
- return new THashSet(strategy);
- }
-
- @NotNull
- @Contract(pure=true)
- public static THashSet newTroveSet(@NotNull T... elements) {
- return newTroveSet(Arrays.asList(elements));
- }
-
- @NotNull
- @Contract(pure=true)
- public static THashSet newTroveSet(@NotNull TObjectHashingStrategy strategy, @NotNull T... elements) {
- return new THashSet(Arrays.asList(elements), strategy);
- }
-
- @NotNull
- @Contract(pure=true)
- public static