MISC: enhance code step 4 (flatten packages & merge kotlin files)
This commit is contained in:
parent
6780c29f94
commit
47d2999207
568
.editorconfig
Normal file
568
.editorconfig
Normal file
@ -0,0 +1,568 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
tab_width = 2
|
||||
ij_continuation_indent_size = 2
|
||||
ij_formatter_off_tag = @fmt:off
|
||||
ij_formatter_on_tag = @fmt:on
|
||||
ij_formatter_tags_enabled = false
|
||||
ij_smart_tabs = true
|
||||
ij_visual_guides = none
|
||||
ij_wrap_on_typing = false
|
||||
|
||||
[*.java]
|
||||
ij_java_align_consecutive_assignments = false
|
||||
ij_java_align_consecutive_variable_declarations = false
|
||||
ij_java_align_group_field_declarations = false
|
||||
ij_java_align_multiline_annotation_parameters = false
|
||||
ij_java_align_multiline_array_initializer_expression = false
|
||||
ij_java_align_multiline_assignment = false
|
||||
ij_java_align_multiline_binary_operation = false
|
||||
ij_java_align_multiline_chained_methods = false
|
||||
ij_java_align_multiline_extends_list = false
|
||||
ij_java_align_multiline_for = true
|
||||
ij_java_align_multiline_method_parentheses = false
|
||||
ij_java_align_multiline_parameters = true
|
||||
ij_java_align_multiline_parameters_in_calls = false
|
||||
ij_java_align_multiline_parenthesized_expression = false
|
||||
ij_java_align_multiline_records = true
|
||||
ij_java_align_multiline_resources = true
|
||||
ij_java_align_multiline_ternary_operation = false
|
||||
ij_java_align_multiline_text_blocks = false
|
||||
ij_java_align_multiline_throws_list = false
|
||||
ij_java_align_subsequent_simple_methods = false
|
||||
ij_java_align_throws_keyword = false
|
||||
ij_java_annotation_parameter_wrap = off
|
||||
ij_java_array_initializer_new_line_after_left_brace = false
|
||||
ij_java_array_initializer_right_brace_on_new_line = false
|
||||
ij_java_array_initializer_wrap = off
|
||||
ij_java_assert_statement_colon_on_next_line = false
|
||||
ij_java_assert_statement_wrap = off
|
||||
ij_java_assignment_wrap = off
|
||||
ij_java_binary_operation_sign_on_next_line = false
|
||||
ij_java_binary_operation_wrap = off
|
||||
ij_java_blank_lines_after_anonymous_class_header = 0
|
||||
ij_java_blank_lines_after_class_header = 0
|
||||
ij_java_blank_lines_after_imports = 1
|
||||
ij_java_blank_lines_after_package = 1
|
||||
ij_java_blank_lines_around_class = 1
|
||||
ij_java_blank_lines_around_field = 0
|
||||
ij_java_blank_lines_around_field_in_interface = 0
|
||||
ij_java_blank_lines_around_initializer = 1
|
||||
ij_java_blank_lines_around_method = 1
|
||||
ij_java_blank_lines_around_method_in_interface = 0
|
||||
ij_java_blank_lines_before_class_end = 0
|
||||
ij_java_blank_lines_before_imports = 1
|
||||
ij_java_blank_lines_before_method_body = 0
|
||||
ij_java_blank_lines_before_package = 0
|
||||
ij_java_block_brace_style = end_of_line
|
||||
ij_java_block_comment_at_first_column = true
|
||||
ij_java_call_parameters_new_line_after_left_paren = false
|
||||
ij_java_call_parameters_right_paren_on_new_line = false
|
||||
ij_java_call_parameters_wrap = off
|
||||
ij_java_case_statement_on_separate_line = true
|
||||
ij_java_catch_on_new_line = false
|
||||
ij_java_class_annotation_wrap = split_into_lines
|
||||
ij_java_class_brace_style = end_of_line
|
||||
ij_java_class_count_to_use_import_on_demand = 5
|
||||
ij_java_class_names_in_javadoc = 1
|
||||
ij_java_do_not_indent_top_level_class_members = false
|
||||
ij_java_do_not_wrap_after_single_annotation = false
|
||||
ij_java_do_while_brace_force = never
|
||||
ij_java_doc_add_blank_line_after_description = true
|
||||
ij_java_doc_add_blank_line_after_param_comments = false
|
||||
ij_java_doc_add_blank_line_after_return = false
|
||||
ij_java_doc_add_p_tag_on_empty_lines = true
|
||||
ij_java_doc_align_exception_comments = true
|
||||
ij_java_doc_align_param_comments = true
|
||||
ij_java_doc_do_not_wrap_if_one_line = true
|
||||
ij_java_doc_enable_formatting = true
|
||||
ij_java_doc_enable_leading_asterisks = true
|
||||
ij_java_doc_indent_on_continuation = false
|
||||
ij_java_doc_keep_empty_lines = true
|
||||
ij_java_doc_keep_empty_parameter_tag = true
|
||||
ij_java_doc_keep_empty_return_tag = true
|
||||
ij_java_doc_keep_empty_throws_tag = true
|
||||
ij_java_doc_keep_invalid_tags = true
|
||||
ij_java_doc_param_description_on_new_line = false
|
||||
ij_java_doc_preserve_line_breaks = false
|
||||
ij_java_doc_use_throws_not_exception_tag = true
|
||||
ij_java_else_on_new_line = false
|
||||
ij_java_enum_constants_wrap = off
|
||||
ij_java_extends_keyword_wrap = off
|
||||
ij_java_extends_list_wrap = off
|
||||
ij_java_field_annotation_wrap = split_into_lines
|
||||
ij_java_finally_on_new_line = false
|
||||
ij_java_for_brace_force = never
|
||||
ij_java_for_statement_new_line_after_left_paren = false
|
||||
ij_java_for_statement_right_paren_on_new_line = false
|
||||
ij_java_for_statement_wrap = off
|
||||
ij_java_generate_final_locals = false
|
||||
ij_java_generate_final_parameters = false
|
||||
ij_java_if_brace_force = never
|
||||
ij_java_imports_layout = *,|,javax.**,java.**,|,$*
|
||||
ij_java_indent_case_from_switch = true
|
||||
ij_java_insert_inner_class_imports = false
|
||||
ij_java_insert_override_annotation = true
|
||||
ij_java_keep_blank_lines_before_right_brace = 2
|
||||
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
|
||||
ij_java_keep_blank_lines_in_code = 2
|
||||
ij_java_keep_blank_lines_in_declarations = 2
|
||||
ij_java_keep_control_statement_in_one_line = true
|
||||
ij_java_keep_first_column_comment = true
|
||||
ij_java_keep_indents_on_empty_lines = false
|
||||
ij_java_keep_line_breaks = true
|
||||
ij_java_keep_multiple_expressions_in_one_line = false
|
||||
ij_java_keep_simple_blocks_in_one_line = false
|
||||
ij_java_keep_simple_classes_in_one_line = false
|
||||
ij_java_keep_simple_lambdas_in_one_line = true
|
||||
ij_java_keep_simple_methods_in_one_line = false
|
||||
ij_java_label_indent_absolute = false
|
||||
ij_java_label_indent_size = 0
|
||||
ij_java_lambda_brace_style = end_of_line
|
||||
ij_java_layout_static_imports_separately = true
|
||||
ij_java_line_comment_add_space = true
|
||||
ij_java_line_comment_at_first_column = false
|
||||
ij_java_method_annotation_wrap = normal
|
||||
ij_java_method_brace_style = end_of_line
|
||||
ij_java_method_call_chain_wrap = off
|
||||
ij_java_method_parameters_new_line_after_left_paren = false
|
||||
ij_java_method_parameters_right_paren_on_new_line = false
|
||||
ij_java_method_parameters_wrap = off
|
||||
ij_java_modifier_list_wrap = false
|
||||
ij_java_names_count_to_use_import_on_demand = 3
|
||||
ij_java_new_line_after_lparen_in_record_header = false
|
||||
ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
|
||||
ij_java_parameter_annotation_wrap = off
|
||||
ij_java_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_java_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_java_place_assignment_sign_on_next_line = false
|
||||
ij_java_prefer_longer_names = true
|
||||
ij_java_prefer_parameters_wrap = false
|
||||
ij_java_record_components_wrap = normal
|
||||
ij_java_repeat_synchronized = true
|
||||
ij_java_replace_instanceof_and_cast = false
|
||||
ij_java_replace_null_check = true
|
||||
ij_java_replace_sum_lambda_with_method_ref = true
|
||||
ij_java_resource_list_new_line_after_left_paren = false
|
||||
ij_java_resource_list_right_paren_on_new_line = false
|
||||
ij_java_resource_list_wrap = off
|
||||
ij_java_rparen_on_new_line_in_record_header = false
|
||||
ij_java_space_after_closing_angle_bracket_in_type_argument = false
|
||||
ij_java_space_after_colon = true
|
||||
ij_java_space_after_comma = true
|
||||
ij_java_space_after_comma_in_type_arguments = true
|
||||
ij_java_space_after_for_semicolon = true
|
||||
ij_java_space_after_quest = true
|
||||
ij_java_space_after_type_cast = true
|
||||
ij_java_space_before_annotation_array_initializer_left_brace = false
|
||||
ij_java_space_before_annotation_parameter_list = false
|
||||
ij_java_space_before_array_initializer_left_brace = false
|
||||
ij_java_space_before_catch_keyword = true
|
||||
ij_java_space_before_catch_left_brace = true
|
||||
ij_java_space_before_catch_parentheses = true
|
||||
ij_java_space_before_class_left_brace = true
|
||||
ij_java_space_before_colon = true
|
||||
ij_java_space_before_colon_in_foreach = true
|
||||
ij_java_space_before_comma = false
|
||||
ij_java_space_before_do_left_brace = true
|
||||
ij_java_space_before_else_keyword = true
|
||||
ij_java_space_before_else_left_brace = true
|
||||
ij_java_space_before_finally_keyword = true
|
||||
ij_java_space_before_finally_left_brace = true
|
||||
ij_java_space_before_for_left_brace = true
|
||||
ij_java_space_before_for_parentheses = true
|
||||
ij_java_space_before_for_semicolon = false
|
||||
ij_java_space_before_if_left_brace = true
|
||||
ij_java_space_before_if_parentheses = true
|
||||
ij_java_space_before_method_call_parentheses = false
|
||||
ij_java_space_before_method_left_brace = true
|
||||
ij_java_space_before_method_parentheses = false
|
||||
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
|
||||
ij_java_space_before_quest = true
|
||||
ij_java_space_before_switch_left_brace = true
|
||||
ij_java_space_before_switch_parentheses = true
|
||||
ij_java_space_before_synchronized_left_brace = true
|
||||
ij_java_space_before_synchronized_parentheses = true
|
||||
ij_java_space_before_try_left_brace = true
|
||||
ij_java_space_before_try_parentheses = true
|
||||
ij_java_space_before_type_parameter_list = false
|
||||
ij_java_space_before_while_keyword = true
|
||||
ij_java_space_before_while_left_brace = true
|
||||
ij_java_space_before_while_parentheses = true
|
||||
ij_java_space_inside_one_line_enum_braces = false
|
||||
ij_java_space_within_empty_array_initializer_braces = false
|
||||
ij_java_space_within_empty_method_call_parentheses = false
|
||||
ij_java_space_within_empty_method_parentheses = false
|
||||
ij_java_spaces_around_additive_operators = true
|
||||
ij_java_spaces_around_assignment_operators = true
|
||||
ij_java_spaces_around_bitwise_operators = true
|
||||
ij_java_spaces_around_equality_operators = true
|
||||
ij_java_spaces_around_lambda_arrow = true
|
||||
ij_java_spaces_around_logical_operators = true
|
||||
ij_java_spaces_around_method_ref_dbl_colon = false
|
||||
ij_java_spaces_around_multiplicative_operators = true
|
||||
ij_java_spaces_around_relational_operators = true
|
||||
ij_java_spaces_around_shift_operators = true
|
||||
ij_java_spaces_around_type_bounds_in_type_parameters = true
|
||||
ij_java_spaces_around_unary_operator = false
|
||||
ij_java_spaces_within_angle_brackets = false
|
||||
ij_java_spaces_within_annotation_parentheses = false
|
||||
ij_java_spaces_within_array_initializer_braces = false
|
||||
ij_java_spaces_within_braces = false
|
||||
ij_java_spaces_within_brackets = false
|
||||
ij_java_spaces_within_cast_parentheses = false
|
||||
ij_java_spaces_within_catch_parentheses = false
|
||||
ij_java_spaces_within_for_parentheses = false
|
||||
ij_java_spaces_within_if_parentheses = false
|
||||
ij_java_spaces_within_method_call_parentheses = false
|
||||
ij_java_spaces_within_method_parentheses = false
|
||||
ij_java_spaces_within_parentheses = false
|
||||
ij_java_spaces_within_record_header = false
|
||||
ij_java_spaces_within_switch_parentheses = false
|
||||
ij_java_spaces_within_synchronized_parentheses = false
|
||||
ij_java_spaces_within_try_parentheses = false
|
||||
ij_java_spaces_within_while_parentheses = false
|
||||
ij_java_special_else_if_treatment = true
|
||||
ij_java_subclass_name_suffix = Impl
|
||||
ij_java_ternary_operation_signs_on_next_line = false
|
||||
ij_java_ternary_operation_wrap = off
|
||||
ij_java_test_name_suffix = Test
|
||||
ij_java_throws_keyword_wrap = off
|
||||
ij_java_throws_list_wrap = off
|
||||
ij_java_use_external_annotations = false
|
||||
ij_java_use_fq_class_names = false
|
||||
ij_java_use_relative_indents = false
|
||||
ij_java_use_single_class_imports = true
|
||||
ij_java_variable_annotation_wrap = off
|
||||
ij_java_visibility = public
|
||||
ij_java_while_brace_force = never
|
||||
ij_java_while_on_new_line = false
|
||||
ij_java_wrap_comments = false
|
||||
ij_java_wrap_first_method_in_call_chain = false
|
||||
ij_java_wrap_long_lines = false
|
||||
|
||||
[*.properties]
|
||||
ij_properties_align_group_field_declarations = false
|
||||
ij_properties_keep_blank_lines = false
|
||||
ij_properties_key_value_delimiter = equals
|
||||
ij_properties_spaces_around_key_value_delimiter = false
|
||||
|
||||
[*.proto]
|
||||
ij_proto_keep_indents_on_empty_lines = false
|
||||
|
||||
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.jspx,*.pom,*.rng,*.tagx,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
|
||||
ij_xml_align_attributes = true
|
||||
ij_xml_align_text = false
|
||||
ij_xml_attribute_wrap = normal
|
||||
ij_xml_block_comment_at_first_column = true
|
||||
ij_xml_keep_blank_lines = 1
|
||||
ij_xml_keep_indents_on_empty_lines = false
|
||||
ij_xml_keep_line_breaks = true
|
||||
ij_xml_keep_line_breaks_in_text = true
|
||||
ij_xml_keep_whitespaces = false
|
||||
ij_xml_keep_whitespaces_around_cdata = preserve
|
||||
ij_xml_keep_whitespaces_inside_cdata = false
|
||||
ij_xml_line_comment_at_first_column = true
|
||||
ij_xml_space_after_tag_name = false
|
||||
ij_xml_space_around_equals_in_attribute = false
|
||||
ij_xml_space_inside_empty_tag = false
|
||||
ij_xml_text_wrap = normal
|
||||
|
||||
[{*.gant,*.gradle,*.groovy,*.gy}]
|
||||
ij_groovy_align_group_field_declarations = false
|
||||
ij_groovy_align_multiline_array_initializer_expression = false
|
||||
ij_groovy_align_multiline_assignment = false
|
||||
ij_groovy_align_multiline_binary_operation = false
|
||||
ij_groovy_align_multiline_chained_methods = false
|
||||
ij_groovy_align_multiline_extends_list = false
|
||||
ij_groovy_align_multiline_for = true
|
||||
ij_groovy_align_multiline_list_or_map = true
|
||||
ij_groovy_align_multiline_method_parentheses = false
|
||||
ij_groovy_align_multiline_parameters = true
|
||||
ij_groovy_align_multiline_parameters_in_calls = false
|
||||
ij_groovy_align_multiline_resources = true
|
||||
ij_groovy_align_multiline_ternary_operation = false
|
||||
ij_groovy_align_multiline_throws_list = false
|
||||
ij_groovy_align_named_args_in_map = true
|
||||
ij_groovy_align_throws_keyword = false
|
||||
ij_groovy_array_initializer_new_line_after_left_brace = false
|
||||
ij_groovy_array_initializer_right_brace_on_new_line = false
|
||||
ij_groovy_array_initializer_wrap = off
|
||||
ij_groovy_assert_statement_wrap = off
|
||||
ij_groovy_assignment_wrap = off
|
||||
ij_groovy_binary_operation_wrap = off
|
||||
ij_groovy_blank_lines_after_class_header = 0
|
||||
ij_groovy_blank_lines_after_imports = 1
|
||||
ij_groovy_blank_lines_after_package = 1
|
||||
ij_groovy_blank_lines_around_class = 1
|
||||
ij_groovy_blank_lines_around_field = 0
|
||||
ij_groovy_blank_lines_around_field_in_interface = 0
|
||||
ij_groovy_blank_lines_around_method = 1
|
||||
ij_groovy_blank_lines_around_method_in_interface = 1
|
||||
ij_groovy_blank_lines_before_imports = 1
|
||||
ij_groovy_blank_lines_before_method_body = 0
|
||||
ij_groovy_blank_lines_before_package = 0
|
||||
ij_groovy_block_brace_style = end_of_line
|
||||
ij_groovy_block_comment_at_first_column = true
|
||||
ij_groovy_call_parameters_new_line_after_left_paren = false
|
||||
ij_groovy_call_parameters_right_paren_on_new_line = false
|
||||
ij_groovy_call_parameters_wrap = off
|
||||
ij_groovy_catch_on_new_line = false
|
||||
ij_groovy_class_annotation_wrap = split_into_lines
|
||||
ij_groovy_class_brace_style = end_of_line
|
||||
ij_groovy_class_count_to_use_import_on_demand = 5
|
||||
ij_groovy_do_while_brace_force = never
|
||||
ij_groovy_else_on_new_line = false
|
||||
ij_groovy_enum_constants_wrap = off
|
||||
ij_groovy_extends_keyword_wrap = off
|
||||
ij_groovy_extends_list_wrap = off
|
||||
ij_groovy_field_annotation_wrap = off
|
||||
ij_groovy_finally_on_new_line = false
|
||||
ij_groovy_for_brace_force = never
|
||||
ij_groovy_for_statement_new_line_after_left_paren = false
|
||||
ij_groovy_for_statement_right_paren_on_new_line = false
|
||||
ij_groovy_for_statement_wrap = off
|
||||
ij_groovy_if_brace_force = never
|
||||
ij_groovy_import_annotation_wrap = 2
|
||||
ij_groovy_imports_layout = *,|,javax.**,java.**,|,$*
|
||||
ij_groovy_indent_case_from_switch = true
|
||||
ij_groovy_indent_label_blocks = true
|
||||
ij_groovy_insert_inner_class_imports = false
|
||||
ij_groovy_keep_blank_lines_before_right_brace = 2
|
||||
ij_groovy_keep_blank_lines_in_code = 2
|
||||
ij_groovy_keep_blank_lines_in_declarations = 2
|
||||
ij_groovy_keep_control_statement_in_one_line = true
|
||||
ij_groovy_keep_first_column_comment = true
|
||||
ij_groovy_keep_indents_on_empty_lines = false
|
||||
ij_groovy_keep_line_breaks = true
|
||||
ij_groovy_keep_multiple_expressions_in_one_line = false
|
||||
ij_groovy_keep_simple_blocks_in_one_line = false
|
||||
ij_groovy_keep_simple_classes_in_one_line = true
|
||||
ij_groovy_keep_simple_lambdas_in_one_line = true
|
||||
ij_groovy_keep_simple_methods_in_one_line = true
|
||||
ij_groovy_label_indent_absolute = false
|
||||
ij_groovy_label_indent_size = 0
|
||||
ij_groovy_lambda_brace_style = end_of_line
|
||||
ij_groovy_layout_static_imports_separately = true
|
||||
ij_groovy_line_comment_add_space = false
|
||||
ij_groovy_line_comment_at_first_column = true
|
||||
ij_groovy_method_annotation_wrap = off
|
||||
ij_groovy_method_brace_style = end_of_line
|
||||
ij_groovy_method_call_chain_wrap = off
|
||||
ij_groovy_method_parameters_new_line_after_left_paren = false
|
||||
ij_groovy_method_parameters_right_paren_on_new_line = false
|
||||
ij_groovy_method_parameters_wrap = off
|
||||
ij_groovy_modifier_list_wrap = false
|
||||
ij_groovy_names_count_to_use_import_on_demand = 3
|
||||
ij_groovy_parameter_annotation_wrap = off
|
||||
ij_groovy_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_groovy_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_groovy_prefer_parameters_wrap = false
|
||||
ij_groovy_resource_list_new_line_after_left_paren = false
|
||||
ij_groovy_resource_list_right_paren_on_new_line = false
|
||||
ij_groovy_resource_list_wrap = off
|
||||
ij_groovy_space_after_assert_separator = true
|
||||
ij_groovy_space_after_colon = true
|
||||
ij_groovy_space_after_comma = true
|
||||
ij_groovy_space_after_comma_in_type_arguments = true
|
||||
ij_groovy_space_after_for_semicolon = true
|
||||
ij_groovy_space_after_quest = true
|
||||
ij_groovy_space_after_type_cast = true
|
||||
ij_groovy_space_before_annotation_parameter_list = false
|
||||
ij_groovy_space_before_array_initializer_left_brace = false
|
||||
ij_groovy_space_before_assert_separator = false
|
||||
ij_groovy_space_before_catch_keyword = true
|
||||
ij_groovy_space_before_catch_left_brace = true
|
||||
ij_groovy_space_before_catch_parentheses = true
|
||||
ij_groovy_space_before_class_left_brace = true
|
||||
ij_groovy_space_before_closure_left_brace = true
|
||||
ij_groovy_space_before_colon = true
|
||||
ij_groovy_space_before_comma = false
|
||||
ij_groovy_space_before_do_left_brace = true
|
||||
ij_groovy_space_before_else_keyword = true
|
||||
ij_groovy_space_before_else_left_brace = true
|
||||
ij_groovy_space_before_finally_keyword = true
|
||||
ij_groovy_space_before_finally_left_brace = true
|
||||
ij_groovy_space_before_for_left_brace = true
|
||||
ij_groovy_space_before_for_parentheses = true
|
||||
ij_groovy_space_before_for_semicolon = false
|
||||
ij_groovy_space_before_if_left_brace = true
|
||||
ij_groovy_space_before_if_parentheses = true
|
||||
ij_groovy_space_before_method_call_parentheses = false
|
||||
ij_groovy_space_before_method_left_brace = true
|
||||
ij_groovy_space_before_method_parentheses = false
|
||||
ij_groovy_space_before_quest = true
|
||||
ij_groovy_space_before_switch_left_brace = true
|
||||
ij_groovy_space_before_switch_parentheses = true
|
||||
ij_groovy_space_before_synchronized_left_brace = true
|
||||
ij_groovy_space_before_synchronized_parentheses = true
|
||||
ij_groovy_space_before_try_left_brace = true
|
||||
ij_groovy_space_before_try_parentheses = true
|
||||
ij_groovy_space_before_while_keyword = true
|
||||
ij_groovy_space_before_while_left_brace = true
|
||||
ij_groovy_space_before_while_parentheses = true
|
||||
ij_groovy_space_in_named_argument = true
|
||||
ij_groovy_space_in_named_argument_before_colon = false
|
||||
ij_groovy_space_within_empty_array_initializer_braces = false
|
||||
ij_groovy_space_within_empty_method_call_parentheses = false
|
||||
ij_groovy_spaces_around_additive_operators = true
|
||||
ij_groovy_spaces_around_assignment_operators = true
|
||||
ij_groovy_spaces_around_bitwise_operators = true
|
||||
ij_groovy_spaces_around_equality_operators = true
|
||||
ij_groovy_spaces_around_lambda_arrow = true
|
||||
ij_groovy_spaces_around_logical_operators = true
|
||||
ij_groovy_spaces_around_multiplicative_operators = true
|
||||
ij_groovy_spaces_around_regex_operators = true
|
||||
ij_groovy_spaces_around_relational_operators = true
|
||||
ij_groovy_spaces_around_shift_operators = true
|
||||
ij_groovy_spaces_within_annotation_parentheses = false
|
||||
ij_groovy_spaces_within_array_initializer_braces = false
|
||||
ij_groovy_spaces_within_braces = true
|
||||
ij_groovy_spaces_within_brackets = false
|
||||
ij_groovy_spaces_within_cast_parentheses = false
|
||||
ij_groovy_spaces_within_catch_parentheses = false
|
||||
ij_groovy_spaces_within_for_parentheses = false
|
||||
ij_groovy_spaces_within_gstring_injection_braces = false
|
||||
ij_groovy_spaces_within_if_parentheses = false
|
||||
ij_groovy_spaces_within_list_or_map = false
|
||||
ij_groovy_spaces_within_method_call_parentheses = false
|
||||
ij_groovy_spaces_within_method_parentheses = false
|
||||
ij_groovy_spaces_within_parentheses = false
|
||||
ij_groovy_spaces_within_switch_parentheses = false
|
||||
ij_groovy_spaces_within_synchronized_parentheses = false
|
||||
ij_groovy_spaces_within_try_parentheses = false
|
||||
ij_groovy_spaces_within_tuple_expression = false
|
||||
ij_groovy_spaces_within_while_parentheses = false
|
||||
ij_groovy_special_else_if_treatment = true
|
||||
ij_groovy_ternary_operation_wrap = off
|
||||
ij_groovy_throws_keyword_wrap = off
|
||||
ij_groovy_throws_list_wrap = off
|
||||
ij_groovy_use_flying_geese_braces = false
|
||||
ij_groovy_use_fq_class_names = false
|
||||
ij_groovy_use_fq_class_names_in_javadoc = true
|
||||
ij_groovy_use_relative_indents = false
|
||||
ij_groovy_use_single_class_imports = true
|
||||
ij_groovy_variable_annotation_wrap = off
|
||||
ij_groovy_while_brace_force = never
|
||||
ij_groovy_while_on_new_line = false
|
||||
ij_groovy_wrap_long_lines = false
|
||||
|
||||
[{*.kt,*.kts}]
|
||||
ij_kotlin_align_in_columns_case_branch = false
|
||||
ij_kotlin_align_multiline_binary_operation = false
|
||||
ij_kotlin_align_multiline_extends_list = false
|
||||
ij_kotlin_align_multiline_method_parentheses = false
|
||||
ij_kotlin_align_multiline_parameters = true
|
||||
ij_kotlin_align_multiline_parameters_in_calls = false
|
||||
ij_kotlin_allow_trailing_comma = true
|
||||
ij_kotlin_allow_trailing_comma_on_call_site = true
|
||||
ij_kotlin_assignment_wrap = off
|
||||
ij_kotlin_blank_lines_after_class_header = 0
|
||||
ij_kotlin_blank_lines_around_block_when_branches = 0
|
||||
ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1
|
||||
ij_kotlin_block_comment_at_first_column = true
|
||||
ij_kotlin_call_parameters_new_line_after_left_paren = false
|
||||
ij_kotlin_call_parameters_right_paren_on_new_line = false
|
||||
ij_kotlin_call_parameters_wrap = off
|
||||
ij_kotlin_catch_on_new_line = false
|
||||
ij_kotlin_class_annotation_wrap = split_into_lines
|
||||
ij_kotlin_continuation_indent_for_chained_calls = true
|
||||
ij_kotlin_continuation_indent_for_expression_bodies = true
|
||||
ij_kotlin_continuation_indent_in_argument_lists = true
|
||||
ij_kotlin_continuation_indent_in_elvis = true
|
||||
ij_kotlin_continuation_indent_in_if_conditions = true
|
||||
ij_kotlin_continuation_indent_in_parameter_lists = true
|
||||
ij_kotlin_continuation_indent_in_supertype_lists = true
|
||||
ij_kotlin_else_on_new_line = false
|
||||
ij_kotlin_enum_constants_wrap = off
|
||||
ij_kotlin_extends_list_wrap = off
|
||||
ij_kotlin_field_annotation_wrap = on_every_item
|
||||
ij_kotlin_finally_on_new_line = false
|
||||
ij_kotlin_if_rparen_on_new_line = false
|
||||
ij_kotlin_import_nested_classes = false
|
||||
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^
|
||||
ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
|
||||
ij_kotlin_keep_blank_lines_before_right_brace = 2
|
||||
ij_kotlin_keep_blank_lines_in_code = 2
|
||||
ij_kotlin_keep_blank_lines_in_declarations = 2
|
||||
ij_kotlin_keep_first_column_comment = true
|
||||
ij_kotlin_keep_indents_on_empty_lines = false
|
||||
ij_kotlin_keep_line_breaks = true
|
||||
ij_kotlin_lbrace_on_next_line = false
|
||||
ij_kotlin_line_comment_add_space = false
|
||||
ij_kotlin_line_comment_at_first_column = true
|
||||
ij_kotlin_method_annotation_wrap = normal
|
||||
ij_kotlin_method_call_chain_wrap = off
|
||||
ij_kotlin_method_parameters_new_line_after_left_paren = false
|
||||
ij_kotlin_method_parameters_right_paren_on_new_line = false
|
||||
ij_kotlin_method_parameters_wrap = off
|
||||
ij_kotlin_name_count_to_use_star_import = 5
|
||||
ij_kotlin_name_count_to_use_star_import_for_members = 3
|
||||
ij_kotlin_packages_to_use_import_on_demand = java.util.*,io.ktor.**,java.awt.*,javax.swing.*
|
||||
ij_kotlin_parameter_annotation_wrap = off
|
||||
ij_kotlin_space_after_comma = true
|
||||
ij_kotlin_space_after_extend_colon = true
|
||||
ij_kotlin_space_after_type_colon = true
|
||||
ij_kotlin_space_before_catch_parentheses = true
|
||||
ij_kotlin_space_before_comma = false
|
||||
ij_kotlin_space_before_extend_colon = true
|
||||
ij_kotlin_space_before_for_parentheses = true
|
||||
ij_kotlin_space_before_if_parentheses = true
|
||||
ij_kotlin_space_before_lambda_arrow = true
|
||||
ij_kotlin_space_before_type_colon = false
|
||||
ij_kotlin_space_before_when_parentheses = true
|
||||
ij_kotlin_space_before_while_parentheses = true
|
||||
ij_kotlin_spaces_around_additive_operators = true
|
||||
ij_kotlin_spaces_around_assignment_operators = true
|
||||
ij_kotlin_spaces_around_equality_operators = true
|
||||
ij_kotlin_spaces_around_function_type_arrow = true
|
||||
ij_kotlin_spaces_around_logical_operators = true
|
||||
ij_kotlin_spaces_around_multiplicative_operators = true
|
||||
ij_kotlin_spaces_around_range = false
|
||||
ij_kotlin_spaces_around_relational_operators = true
|
||||
ij_kotlin_spaces_around_unary_operator = false
|
||||
ij_kotlin_spaces_around_when_arrow = true
|
||||
ij_kotlin_variable_annotation_wrap = off
|
||||
ij_kotlin_while_on_new_line = false
|
||||
ij_kotlin_wrap_elvis_expressions = 1
|
||||
ij_kotlin_wrap_expression_body_functions = 0
|
||||
ij_kotlin_wrap_first_method_in_call_chain = false
|
||||
|
||||
[{*.har,*.json}]
|
||||
ij_json_keep_blank_lines_in_code = 0
|
||||
ij_json_keep_indents_on_empty_lines = false
|
||||
ij_json_keep_line_breaks = true
|
||||
ij_json_space_after_colon = true
|
||||
ij_json_space_after_comma = true
|
||||
ij_json_space_before_colon = true
|
||||
ij_json_space_before_comma = false
|
||||
ij_json_spaces_within_braces = false
|
||||
ij_json_spaces_within_brackets = false
|
||||
ij_json_wrap_long_lines = false
|
||||
|
||||
[{*.markdown,*.md}]
|
||||
ij_markdown_force_one_space_after_blockquote_symbol = true
|
||||
ij_markdown_force_one_space_after_header_symbol = true
|
||||
ij_markdown_force_one_space_after_list_bullet = true
|
||||
ij_markdown_force_one_space_between_words = true
|
||||
ij_markdown_keep_indents_on_empty_lines = false
|
||||
ij_markdown_max_lines_around_block_elements = 1
|
||||
ij_markdown_max_lines_around_header = 1
|
||||
ij_markdown_max_lines_between_paragraphs = 1
|
||||
ij_markdown_min_lines_around_block_elements = 1
|
||||
ij_markdown_min_lines_around_header = 1
|
||||
ij_markdown_min_lines_between_paragraphs = 1
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
ij_yaml_keep_indents_on_empty_lines = false
|
||||
ij_yaml_keep_line_breaks = true
|
||||
ij_yaml_space_before_colon = true
|
||||
ij_yaml_spaces_within_braces = true
|
||||
ij_yaml_spaces_within_brackets = true
|
@ -125,22 +125,22 @@
|
||||
</activity-alias>
|
||||
|
||||
<activity
|
||||
android:name=".ui.support.AboutActivity"
|
||||
android:name=".ui.other.AboutActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/about"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
<activity
|
||||
android:name=".ui.crash.CrashActivity"
|
||||
android:name=".ui.other.CrashActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/error"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
<activity
|
||||
android:name=".ui.setup.SetupActivity"
|
||||
android:name=".ui.other.SetupActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".ui.bonus.BonusActivity"
|
||||
android:name=".ui.other.BonusActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
@ -159,12 +159,6 @@
|
||||
android:exported="false"
|
||||
android:label="@string/pref_customization_color_scheme"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
<activity
|
||||
android:name=".ui.support.HelpActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/faq"
|
||||
android:theme="@style/AppTheme.NoActionBar.Dark"/>
|
||||
|
||||
<activity
|
||||
android:name=".ui.settings.SettingActivity"
|
||||
android:exported="false"
|
||||
|
@ -9,8 +9,8 @@ import android.view.Gravity
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import io.neoterm.component.NeoInitializer
|
||||
import io.neoterm.frontend.config.NeoPreference
|
||||
import io.neoterm.ui.bonus.BonusActivity
|
||||
import io.neoterm.component.config.NeoPreference
|
||||
import io.neoterm.ui.other.BonusActivity
|
||||
import io.neoterm.utils.CrashHandler
|
||||
|
||||
/**
|
||||
|
@ -10,10 +10,9 @@ import io.neoterm.component.font.FontComponent
|
||||
import io.neoterm.component.pm.PackageComponent
|
||||
import io.neoterm.component.profile.ProfileComponent
|
||||
import io.neoterm.component.session.SessionComponent
|
||||
import io.neoterm.component.session.ShellProfile
|
||||
import io.neoterm.component.userscript.UserScriptComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.session.shell.ShellProfile
|
||||
import io.neoterm.utils.NLog
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
|
@ -1,6 +0,0 @@
|
||||
package io.neoterm.component.codegen
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class CodeGenParameter
|
@ -1,12 +1,8 @@
|
||||
package io.neoterm.component.codegen
|
||||
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenObject
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenerator
|
||||
import io.neoterm.frontend.component.NeoComponent
|
||||
import io.neoterm.component.NeoComponent
|
||||
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class CodeGenComponent : NeoComponent {
|
||||
override fun onServiceInit() {
|
||||
}
|
||||
@ -23,3 +19,4 @@ class CodeGenComponent : NeoComponent {
|
||||
}
|
||||
}
|
||||
|
||||
class CodeGenParameter
|
@ -1,15 +1,9 @@
|
||||
package io.neoterm.component.codegen.generators
|
||||
package io.neoterm.component.codegen
|
||||
|
||||
import io.neoterm.component.codegen.CodeGenParameter
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenObject
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenerator
|
||||
import io.neoterm.component.ComponentManager
|
||||
import io.neoterm.component.colorscheme.NeoColorScheme
|
||||
import io.neoterm.component.config.ConfigureComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoColorGenerator(parameter: CodeGenParameter) : CodeGenerator(parameter) {
|
||||
override fun getGeneratorName(): String {
|
||||
return "NeoColorScheme-Generator"
|
||||
@ -44,7 +38,7 @@ class NeoColorGenerator(parameter: CodeGenParameter) : CodeGenerator(parameter)
|
||||
" ${NeoColorScheme.COLOR_META_VERSION}: ${
|
||||
colorScheme.colorVersion
|
||||
?: component.getLoaderVersion()
|
||||
}\n"
|
||||
}\n",
|
||||
)
|
||||
builder.append("\n")
|
||||
}
|
||||
@ -62,3 +56,13 @@ class NeoColorGenerator(parameter: CodeGenParameter) : CodeGenerator(parameter)
|
||||
builder.append(" }\n")
|
||||
}
|
||||
}
|
||||
|
||||
class NeoProfileGenerator(parameter: CodeGenParameter) : CodeGenerator(parameter) {
|
||||
override fun getGeneratorName(): String {
|
||||
return "NeoProfile-Generator"
|
||||
}
|
||||
|
||||
override fun generateCode(codeGenObject: CodeGenObject): String {
|
||||
return ""
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package io.neoterm.component.codegen.generators
|
||||
|
||||
import io.neoterm.component.codegen.CodeGenParameter
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenObject
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenerator
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoProfileGenerator(parameter: CodeGenParameter) : CodeGenerator(parameter) {
|
||||
override fun getGeneratorName(): String {
|
||||
return "NeoProfile-Generator"
|
||||
}
|
||||
|
||||
override fun generateCode(codeGenObject: CodeGenObject): String {
|
||||
return ""
|
||||
}
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
package io.neoterm.component.codegen.interfaces
|
||||
package io.neoterm.component.codegen
|
||||
|
||||
import io.neoterm.component.codegen.CodeGenParameter
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
abstract class CodeGenerator(parameter: CodeGenParameter) {
|
||||
abstract fun getGeneratorName(): String
|
||||
|
||||
abstract fun generateCode(codeGenObject: CodeGenObject): String
|
||||
}
|
||||
|
||||
interface CodeGenObject {
|
||||
fun getCodeGenerator(parameter: CodeGenParameter): CodeGenerator
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package io.neoterm.component.codegen.interfaces
|
||||
|
||||
import io.neoterm.component.codegen.CodeGenParameter
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface CodeGenObject {
|
||||
fun getCodeGenerator(parameter: CodeGenParameter): CodeGenerator
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package io.neoterm.component.colorscheme
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object DefaultColorScheme : NeoColorScheme() {
|
||||
init {
|
||||
/* NOTE: Keep in sync with assets/colors/Default.nl */
|
||||
colorName = "Default"
|
||||
|
||||
foregroundColor = "#ffffff"
|
||||
backgroundColor = "#14181c"
|
||||
cursorColor = "#a9aaa9"
|
||||
}
|
||||
}
|
@ -4,20 +4,17 @@ import android.content.Context
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.App
|
||||
import io.neoterm.R
|
||||
import io.neoterm.component.ComponentManager
|
||||
import io.neoterm.component.ConfigFileBasedComponent
|
||||
import io.neoterm.component.codegen.CodeGenComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.component.helper.ConfigFileBasedComponent
|
||||
import io.neoterm.frontend.config.NeoPreference
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.component.config.NeoPreference
|
||||
import io.neoterm.component.config.NeoTermPath
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
import io.neoterm.frontend.session.view.extrakey.ExtraKeysView
|
||||
import io.neoterm.utils.extractAssetsDir
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ColorSchemeComponent : ConfigFileBasedComponent<NeoColorScheme>(NeoTermPath.COLORS_PATH) {
|
||||
companion object {
|
||||
fun colorFile(colorName: String): File {
|
||||
@ -121,3 +118,4 @@ class ColorSchemeComponent : ConfigFileBasedComponent<NeoColorScheme>(NeoTermPat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,23 +3,15 @@ package io.neoterm.component.colorscheme
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.backend.TerminalColorScheme
|
||||
import io.neoterm.backend.TerminalColors
|
||||
import io.neoterm.component.ConfigFileBasedObject
|
||||
import io.neoterm.component.codegen.CodeGenObject
|
||||
import io.neoterm.component.codegen.CodeGenParameter
|
||||
import io.neoterm.component.codegen.generators.NeoColorGenerator
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenObject
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenerator
|
||||
import io.neoterm.component.config.ConfigureComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.component.helper.ConfigFileBasedObject
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.io.File
|
||||
import io.neoterm.component.codegen.CodeGenerator
|
||||
import io.neoterm.component.codegen.NeoColorGenerator
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
import io.neoterm.frontend.session.view.extrakey.ExtraKeysView
|
||||
import io.neoterm.utils.NLog
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class NeoColorScheme : CodeGenObject, ConfigFileBasedObject {
|
||||
companion object {
|
||||
const val COLOR_PREFIX = "color"
|
||||
@ -173,24 +165,15 @@ open class NeoColorScheme : CodeGenObject, ConfigFileBasedObject {
|
||||
private fun getColorByVisitor(visitor: ConfigVisitor, colorName: String): String? {
|
||||
return visitor.getStringValue(COLOR_PATH, colorName)
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun testLoadConfigure(file: File): Boolean {
|
||||
val loaderService = ComponentManager.getComponent<ConfigureComponent>()
|
||||
object DefaultColorScheme : NeoColorScheme() {
|
||||
init {
|
||||
/* NOTE: Keep in sync with assets/colors/Default.nl */
|
||||
colorName = "Default"
|
||||
|
||||
val configure: NeoConfigureFile?
|
||||
try {
|
||||
configure = loaderService.newLoader(file).loadConfigure()
|
||||
if (configure == null) {
|
||||
throw RuntimeException("Parse configuration failed.")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
NLog.e("ExtraKey", "Failed to load extra key config: ${file.absolutePath}: ${e.localizedMessage}")
|
||||
return false
|
||||
}
|
||||
|
||||
val visitor = configure.getVisitor()
|
||||
onConfigLoaded(visitor)
|
||||
return true
|
||||
foregroundColor = "#ffffff"
|
||||
backgroundColor = "#14181c"
|
||||
cursorColor = "#a9aaa9"
|
||||
}
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
package io.neoterm.frontend.component
|
||||
package io.neoterm.component
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface NeoComponent {
|
||||
fun onServiceInit()
|
||||
fun onServiceDestroy()
|
||||
fun onServiceObtained()
|
||||
}
|
||||
|
||||
object ComponentManager {
|
||||
private val COMPONENTS = ConcurrentHashMap<Class<out NeoComponent>, NeoComponent>()
|
||||
|
||||
@ -43,3 +46,7 @@ object ComponentManager {
|
||||
return componentInterface.newInstance()
|
||||
}
|
||||
}
|
||||
|
||||
class ComponentDuplicateException(serviceName: String) : RuntimeException("Service $serviceName duplicate")
|
||||
class ComponentNotFoundException(serviceName: String) : RuntimeException("Component `$serviceName' not found")
|
||||
|
@ -1,22 +0,0 @@
|
||||
package io.neoterm.component.completion
|
||||
|
||||
import io.neoterm.component.completion.provider.FileCompletionProvider
|
||||
import io.neoterm.component.completion.provider.ProgramCompletionProvider
|
||||
import io.neoterm.frontend.completion.CompletionManager
|
||||
import io.neoterm.frontend.component.NeoComponent
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class CompletionComponent : NeoComponent {
|
||||
override fun onServiceInit() {
|
||||
CompletionManager.registerProvider(FileCompletionProvider())
|
||||
CompletionManager.registerProvider(ProgramCompletionProvider())
|
||||
}
|
||||
|
||||
override fun onServiceDestroy() {
|
||||
}
|
||||
|
||||
override fun onServiceObtained() {
|
||||
}
|
||||
}
|
@ -1,11 +1,20 @@
|
||||
package io.neoterm.frontend.completion
|
||||
package io.neoterm.component.completion
|
||||
|
||||
import io.neoterm.frontend.completion.model.CompletionResult
|
||||
import io.neoterm.frontend.completion.provider.ICandidateProvider
|
||||
import io.neoterm.component.NeoComponent
|
||||
|
||||
class CompletionComponent : NeoComponent {
|
||||
override fun onServiceInit() {
|
||||
CompletionManager.registerProvider(FileCompletionProvider())
|
||||
CompletionManager.registerProvider(ProgramCompletionProvider())
|
||||
}
|
||||
|
||||
override fun onServiceDestroy() {
|
||||
}
|
||||
|
||||
override fun onServiceObtained() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object CompletionManager {
|
||||
private val candidateProviders = mutableMapOf<String, ICandidateProvider>()
|
||||
|
||||
@ -38,3 +47,22 @@ object CompletionManager {
|
||||
.takeWhile { it.canComplete(text) })
|
||||
}
|
||||
}
|
||||
|
||||
class ProviderDetector(val providers: List<ICandidateProvider>) : MarkScoreListener {
|
||||
private var detectedProvider: ICandidateProvider? = null
|
||||
|
||||
override fun onMarkScore(score: Int) {
|
||||
// TODO: Save provider score
|
||||
}
|
||||
|
||||
fun detectBest(): ICandidateProvider? {
|
||||
// TODO: detect best
|
||||
detectedProvider = if (providers.isEmpty())
|
||||
null
|
||||
else
|
||||
providers[0]
|
||||
|
||||
return detectedProvider
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package io.neoterm.frontend.completion.model
|
||||
package io.neoterm.component.completion
|
||||
|
||||
import io.neoterm.frontend.completion.listener.MarkScoreListener
|
||||
class CompletionCandidate(val completeString: String) {
|
||||
var displayName: String = completeString
|
||||
var description: String? = null
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class CompletionResult(val candidates: List<CompletionCandidate>, var scoreMarker: MarkScoreListener) {
|
||||
fun markScore(score: Int) {
|
||||
scoreMarker.onMarkScore(score)
|
||||
@ -14,3 +14,4 @@ class CompletionResult(val candidates: List<CompletionCandidate>, var scoreMarke
|
||||
return candidates.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package io.neoterm.component.completion
|
||||
|
||||
interface MarkScoreListener {
|
||||
fun onMarkScore(score: Int)
|
||||
}
|
||||
|
||||
interface OnAutoCompleteListener {
|
||||
fun onCompletionRequired(newText: String?)
|
||||
fun onKeyCode(keyCode: Int, keyMod: Int)
|
||||
fun onCleanUp()
|
||||
fun onFinishCompletion(): Boolean
|
||||
}
|
||||
|
||||
interface OnCandidateSelectedListener {
|
||||
fun onCandidateSelected(candidate: CompletionCandidate)
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package io.neoterm.component.completion.provider
|
||||
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ProgramCompletionProvider : FileCompletionProvider() {
|
||||
override val providerName: String
|
||||
get() = "NeoTermProvider.ProgramCompletionProvider"
|
||||
|
||||
|
||||
override fun generateDesc(file: File): String? {
|
||||
return if (file.canExecute()) "<Program>" else super.generateDesc(file)
|
||||
}
|
||||
}
|
@ -1,18 +1,18 @@
|
||||
package io.neoterm.component.completion.provider
|
||||
package io.neoterm.component.completion
|
||||
|
||||
import io.neoterm.frontend.completion.model.CompletionCandidate
|
||||
import io.neoterm.frontend.completion.provider.ICandidateProvider
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface ICandidateProvider {
|
||||
val providerName: String
|
||||
fun provideCandidates(text: String): List<CompletionCandidate>
|
||||
fun canComplete(text: String): Boolean
|
||||
}
|
||||
|
||||
open class FileCompletionProvider : ICandidateProvider {
|
||||
override val providerName: String
|
||||
get() = "NeoTermProvider.FileCompletionProvider"
|
||||
|
||||
override fun provideCandidates(text: String): List<CompletionCandidate>? {
|
||||
override fun provideCandidates(text: String): List<CompletionCandidate> {
|
||||
var file = File(text)
|
||||
var filter: ((File) -> Boolean)? = null
|
||||
|
||||
@ -33,20 +33,14 @@ open class FileCompletionProvider : ICandidateProvider {
|
||||
return if (filter != null) path.listFiles(filter) else path.listFiles()
|
||||
}
|
||||
|
||||
private fun generateCandidateList(file: File, filter: ((File) -> Boolean)?): List<CompletionCandidate>? {
|
||||
if (file.canRead()) {
|
||||
val candidates = mutableListOf<CompletionCandidate>()
|
||||
listDirectory(file, filter)
|
||||
.mapTo(candidates, {
|
||||
private fun generateCandidateList(file: File, filter: ((File) -> Boolean)?) =
|
||||
if (file.canRead()) listDirectory(file, filter).map {
|
||||
val candidate = CompletionCandidate(it.name)
|
||||
candidate.description = generateDesc(it)
|
||||
candidate.displayName = generateDisplayName(it)
|
||||
candidate
|
||||
})
|
||||
return candidates
|
||||
}
|
||||
return null
|
||||
}
|
||||
}.toList()
|
||||
else listOf()
|
||||
|
||||
open fun generateDisplayName(file: File): String {
|
||||
return if (file.isDirectory) "${file.name}/" else file.name
|
||||
@ -56,3 +50,13 @@ open class FileCompletionProvider : ICandidateProvider {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class ProgramCompletionProvider : FileCompletionProvider() {
|
||||
override val providerName: String
|
||||
get() = "NeoTermProvider.ProgramCompletionProvider"
|
||||
|
||||
|
||||
override fun generateDesc(file: File): String? {
|
||||
return if (file.canExecute()) "<Program>" else super.generateDesc(file)
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package io.neoterm.component.config
|
||||
|
||||
import io.neoterm.component.config.loaders.NeoLangConfigureLoader
|
||||
import io.neoterm.component.config.loaders.OldConfigureLoader
|
||||
import io.neoterm.frontend.component.NeoComponent
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ConfigureComponent : NeoComponent {
|
||||
val CONFIG_LOADER_VERSION = 20
|
||||
|
||||
override fun onServiceInit() {
|
||||
}
|
||||
|
||||
override fun onServiceDestroy() {
|
||||
}
|
||||
|
||||
override fun onServiceObtained() {
|
||||
}
|
||||
|
||||
fun getLoaderVersion(): Int {
|
||||
return CONFIG_LOADER_VERSION
|
||||
}
|
||||
|
||||
fun newLoader(configFile: File): IConfigureLoader {
|
||||
return when (configFile.extension) {
|
||||
"nl" -> NeoLangConfigureLoader(configFile)
|
||||
else -> OldConfigureLoader(configFile)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package io.neoterm.component.config
|
||||
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface IConfigureLoader {
|
||||
fun loadConfigure(): NeoConfigureFile?
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.config
|
||||
package io.neoterm.component.config
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
@ -6,18 +6,59 @@ import android.preference.PreferenceManager
|
||||
import android.system.ErrnoException
|
||||
import android.system.Os
|
||||
import android.util.TypedValue
|
||||
import io.neolang.parser.NeoLangParser
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.App
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.component.NeoComponent
|
||||
import io.neoterm.services.NeoTermService
|
||||
import io.neoterm.utils.NLog
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
class ConfigureComponent : NeoComponent {
|
||||
override fun onServiceInit() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
override fun onServiceDestroy() {
|
||||
}
|
||||
|
||||
override fun onServiceObtained() {
|
||||
}
|
||||
|
||||
fun getLoaderVersion(): Int {
|
||||
return CONFIG_LOADER_VERSION
|
||||
}
|
||||
|
||||
fun newLoader(configFile: File): IConfigureLoader {
|
||||
return when (configFile.extension) {
|
||||
"nl" -> NeoLangConfigureLoader(configFile)
|
||||
else -> OldConfigureLoader(configFile)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val CONFIG_LOADER_VERSION = 20
|
||||
}
|
||||
}
|
||||
|
||||
open class NeoConfigureFile(val configureFile: File) {
|
||||
private val configParser = NeoLangParser()
|
||||
protected open var configVisitor: ConfigVisitor? = null
|
||||
|
||||
fun getVisitor() = configVisitor ?: throw IllegalStateException("Configure file not loaded or parse failed.")
|
||||
|
||||
open fun parseConfigure() = kotlin.runCatching {
|
||||
val programCode = String(Files.readAllBytes(configureFile.toPath()))
|
||||
configParser.setInputSource(programCode)
|
||||
|
||||
val ast = configParser.parse()
|
||||
val astVisitor = ast.visit().getVisitor(ConfigVisitor::class.java) ?: return false
|
||||
astVisitor.start()
|
||||
configVisitor = astVisitor.getCallback()
|
||||
}.isSuccess
|
||||
}
|
||||
|
||||
object NeoPreference {
|
||||
const val KEY_HAPPY_EGG = "neoterm_fun_happy"
|
@ -1,10 +1,28 @@
|
||||
package io.neoterm.frontend.config
|
||||
package io.neoterm.component.config
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object DefaultValues {
|
||||
const val fontSize = 30
|
||||
|
||||
const val enableBell = false
|
||||
const val enableVibrate = false
|
||||
const val enableExecveWrapper = true
|
||||
const val enableAutoCompletion = false
|
||||
const val enableFullScreen = false
|
||||
const val enableAutoHideToolbar = false
|
||||
const val enableSwitchNextTab = false
|
||||
const val enableExtraKeys = true
|
||||
const val enableExplicitExtraKeysWeight = false
|
||||
const val enableBackButtonBeMappedToEscape = false
|
||||
const val enableSpecialVolumeKeys = false
|
||||
const val enableWordBasedIme = false
|
||||
|
||||
const val loginShell = "bash"
|
||||
const val initialCommand = ""
|
||||
const val defaultFont = "SourceCodePro"
|
||||
}
|
||||
|
||||
object NeoTermPath {
|
||||
@SuppressLint("SdCardPath")
|
||||
const val ROOT_PATH = "/data/data/io.neoterm/files"
|
194
app/src/main/java/io/neoterm/component/config/loaders.kt
Normal file
194
app/src/main/java/io/neoterm/component/config/loaders.kt
Normal file
@ -0,0 +1,194 @@
|
||||
package io.neoterm.component.config
|
||||
|
||||
import io.neolang.runtime.type.NeoLangValue
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.component.colorscheme.NeoColorScheme
|
||||
import io.neoterm.component.extrakey.NeoExtraKey
|
||||
import io.neoterm.frontend.session.view.extrakey.TextButton
|
||||
import io.neoterm.utils.NLog
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileReader
|
||||
import java.util.*
|
||||
|
||||
interface IConfigureLoader {
|
||||
fun loadConfigure(): NeoConfigureFile?
|
||||
}
|
||||
|
||||
class NeoLangConfigureLoader(private val configFile: File) : IConfigureLoader {
|
||||
override fun loadConfigure(): NeoConfigureFile? {
|
||||
val configureFile = NeoConfigureFile(configFile)
|
||||
return if (configureFile.parseConfigure()) configureFile else null
|
||||
}
|
||||
}
|
||||
|
||||
class OldConfigureLoader(private val configFile: File) : IConfigureLoader {
|
||||
override fun loadConfigure(): NeoConfigureFile? {
|
||||
return when (configFile.extension) {
|
||||
"eks" -> returnConfigure(OldExtraKeysConfigureFile(configFile))
|
||||
"color" -> returnConfigure(OldColorSchemeConfigureFile(configFile))
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun returnConfigure(configureFile: NeoConfigureFile): NeoConfigureFile? {
|
||||
return if (configureFile.parseConfigure()) configureFile else null
|
||||
}
|
||||
|
||||
companion object {
|
||||
class OldColorSchemeConfigureFile(configureFile: File) : NeoConfigureFile(configureFile) {
|
||||
override var configVisitor: ConfigVisitor? = null
|
||||
|
||||
override fun parseConfigure(): Boolean {
|
||||
try {
|
||||
val visitor = ConfigVisitor()
|
||||
visitor.onStart()
|
||||
visitor.onEnterContext(NeoColorScheme.CONTEXT_META_NAME)
|
||||
|
||||
visitor.getCurrentContext()
|
||||
.defineAttribute(NeoColorScheme.COLOR_META_NAME, NeoLangValue(configureFile.nameWithoutExtension))
|
||||
.defineAttribute(NeoColorScheme.COLOR_META_VERSION, NeoLangValue("1.0"))
|
||||
|
||||
visitor.onEnterContext(NeoColorScheme.CONTEXT_COLOR_NAME)
|
||||
|
||||
return FileInputStream(configureFile).use {
|
||||
val prop = Properties()
|
||||
prop.load(it)
|
||||
prop.forEach {
|
||||
visitor.getCurrentContext().defineAttribute(it.key as String, NeoLangValue(it.value as String))
|
||||
}
|
||||
visitor.onFinish()
|
||||
this.configVisitor = visitor
|
||||
true
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
this.configVisitor = null
|
||||
NLog.e("ConfigureLoader", "Error while loading old config", e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
class OldExtraKeysConfigureFile(configureFile: File) : NeoConfigureFile(configureFile) {
|
||||
override var configVisitor: ConfigVisitor? = null
|
||||
|
||||
override fun parseConfigure(): Boolean {
|
||||
try {
|
||||
val config = parseOldConfig(BufferedReader(FileReader(configureFile)))
|
||||
return generateVisitor(config)
|
||||
} catch (e: Exception) {
|
||||
NLog.e("ConfigureLoader", "Failed to load old extra keys config: ${e.localizedMessage}")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateVisitor(config: NeoExtraKey): Boolean {
|
||||
configVisitor = ConfigVisitor()
|
||||
val visitor = configVisitor!!
|
||||
visitor.onStart()
|
||||
visitor.onEnterContext(NeoExtraKey.EKS_META_CONTEXT_NAME)
|
||||
visitor.getCurrentContext()
|
||||
.defineAttribute(NeoExtraKey.EKS_META_VERSION, NeoLangValue(config.version))
|
||||
.defineAttribute(NeoExtraKey.EKS_META_WITH_DEFAULT, NeoLangValue(config.withDefaultKeys))
|
||||
|
||||
// program
|
||||
visitor.onEnterContext(NeoExtraKey.EKS_META_PROGRAM)
|
||||
config.programNames.forEachIndexed { index, program ->
|
||||
visitor.getCurrentContext().defineAttribute(index.toString(), NeoLangValue(program))
|
||||
}
|
||||
visitor.onExitContext()
|
||||
|
||||
// key
|
||||
visitor.onEnterContext(NeoExtraKey.EKS_META_KEY)
|
||||
config.shortcutKeys.forEachIndexed { index, button ->
|
||||
if (button is TextButton) {
|
||||
visitor.onEnterContext(index.toString())
|
||||
visitor.getCurrentContext()
|
||||
.defineAttribute(NeoExtraKey.EKS_META_WITH_ENTER, NeoLangValue(button.withEnter))
|
||||
.defineAttribute(NeoExtraKey.EKS_META_DISPLAY, NeoLangValue(button.buttonKeys!!))
|
||||
.defineAttribute(NeoExtraKey.EKS_META_CODE, NeoLangValue(button.buttonKeys!!))
|
||||
visitor.onExitContext()
|
||||
}
|
||||
}
|
||||
visitor.onExitContext()
|
||||
|
||||
visitor.onFinish()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun parseOldConfig(source: BufferedReader): NeoExtraKey {
|
||||
val config = NeoExtraKey()
|
||||
var line: String? = source.readLine()
|
||||
|
||||
while (line != null) {
|
||||
line = line.trim().trimEnd()
|
||||
if (line.isEmpty() || line.startsWith("#")) {
|
||||
line = source.readLine()
|
||||
continue
|
||||
}
|
||||
|
||||
if (line.startsWith(NeoExtraKey.EKS_META_VERSION)) {
|
||||
parseHeader(line, config)
|
||||
} else if (line.startsWith(NeoExtraKey.EKS_META_PROGRAM)) {
|
||||
parseProgram(line, config)
|
||||
} else if (line.startsWith("define")) {
|
||||
parseKeyDefine(line, config)
|
||||
} else if (line.startsWith(NeoExtraKey.EKS_META_WITH_DEFAULT)) {
|
||||
parseWithDefault(line, config)
|
||||
}
|
||||
line = source.readLine()
|
||||
}
|
||||
|
||||
if (config.version < 0) {
|
||||
throw RuntimeException("Not a valid shortcut config file")
|
||||
}
|
||||
if (config.programNames.size == 0) {
|
||||
throw RuntimeException("At least one program name should be given")
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
private fun parseWithDefault(line: String, config: NeoExtraKey) {
|
||||
val value = line.substring(NeoExtraKey.EKS_META_WITH_DEFAULT.length).trim().trimEnd()
|
||||
config.withDefaultKeys = value == "true"
|
||||
}
|
||||
|
||||
private fun parseKeyDefine(line: String, config: NeoExtraKey) {
|
||||
val keyDefine = line.substring("define".length).trim().trimEnd()
|
||||
val keyValues = keyDefine.split(" ")
|
||||
if (keyValues.size < 2) {
|
||||
throw RuntimeException("Bad define")
|
||||
}
|
||||
|
||||
val buttonText = keyValues[0]
|
||||
val withEnter = keyValues[1] == "true"
|
||||
|
||||
config.shortcutKeys.add(TextButton(buttonText, withEnter))
|
||||
}
|
||||
|
||||
private fun parseProgram(line: String, config: NeoExtraKey) {
|
||||
val programNames = line.substring(NeoExtraKey.EKS_META_PROGRAM.length).trim().trimEnd()
|
||||
if (programNames.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
for (name in programNames.split(" ")) {
|
||||
config.programNames.add(name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseHeader(line: String, config: NeoExtraKey) {
|
||||
val version: Int
|
||||
val versionString = line.substring(NeoExtraKey.EKS_META_VERSION.length).trim().trimEnd()
|
||||
try {
|
||||
version = Integer.parseInt(versionString)
|
||||
} catch (e: NumberFormatException) {
|
||||
throw RuntimeException("Bad version '$versionString'")
|
||||
}
|
||||
|
||||
config.version = version
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package io.neoterm.component.config.loaders
|
||||
|
||||
import io.neoterm.component.config.IConfigureLoader
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangConfigureLoader(private val configFile: File) : IConfigureLoader {
|
||||
override fun loadConfigure(): NeoConfigureFile? {
|
||||
val configureFile = NeoConfigureFile(configFile)
|
||||
return if (configureFile.parseConfigure()) configureFile else null
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package io.neoterm.component.config.loaders
|
||||
|
||||
import io.neolang.runtime.type.NeoLangValue
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.component.colorscheme.NeoColorScheme
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class OldColorSchemeConfigureFile(configureFile: File) : NeoConfigureFile(configureFile) {
|
||||
override var configVisitor: ConfigVisitor? = null
|
||||
|
||||
override fun parseConfigure(): Boolean {
|
||||
try {
|
||||
val visitor = ConfigVisitor()
|
||||
visitor.onStart()
|
||||
visitor.onEnterContext(NeoColorScheme.CONTEXT_META_NAME)
|
||||
|
||||
visitor.getCurrentContext()
|
||||
.defineAttribute(NeoColorScheme.COLOR_META_NAME, NeoLangValue(configureFile.nameWithoutExtension))
|
||||
.defineAttribute(NeoColorScheme.COLOR_META_VERSION, NeoLangValue("1.0"))
|
||||
|
||||
visitor.onEnterContext(NeoColorScheme.CONTEXT_COLOR_NAME)
|
||||
|
||||
return FileInputStream(configureFile).use {
|
||||
val prop = Properties()
|
||||
prop.load(it)
|
||||
prop.forEach {
|
||||
visitor.getCurrentContext().defineAttribute(it.key as String, NeoLangValue(it.value as String))
|
||||
}
|
||||
visitor.onFinish()
|
||||
this.configVisitor = visitor
|
||||
true
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
this.configVisitor = null
|
||||
NLog.e("ConfigureLoader", "Error while loading old config", e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package io.neoterm.component.config.loaders
|
||||
|
||||
import io.neoterm.component.config.IConfigureLoader
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class OldConfigureLoader(private val configFile: File) : IConfigureLoader {
|
||||
override fun loadConfigure(): NeoConfigureFile? {
|
||||
return when (configFile.extension) {
|
||||
"eks" -> returnConfigure(OldExtraKeysConfigureFile(configFile))
|
||||
"color" -> returnConfigure(OldColorSchemeConfigureFile(configFile))
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun returnConfigure(configureFile: NeoConfigureFile): NeoConfigureFile? {
|
||||
return if (configureFile.parseConfigure()) configureFile else null
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
package io.neoterm.component.config.loaders
|
||||
|
||||
import io.neolang.runtime.type.NeoLangValue
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.component.extrakey.NeoExtraKey
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.terminal.extrakey.button.TextButton
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class OldExtraKeysConfigureFile(configureFile: File) : NeoConfigureFile(configureFile) {
|
||||
override var configVisitor: ConfigVisitor? = null
|
||||
|
||||
override fun parseConfigure(): Boolean {
|
||||
try {
|
||||
val config = parseOldConfig(BufferedReader(FileReader(configureFile)))
|
||||
return generateVisitor(config)
|
||||
} catch (e: Exception) {
|
||||
NLog.e("ConfigureLoader", "Failed to load old extra keys config: ${e.localizedMessage}")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateVisitor(config: NeoExtraKey): Boolean {
|
||||
configVisitor = ConfigVisitor()
|
||||
val visitor = configVisitor!!
|
||||
visitor.onStart()
|
||||
visitor.onEnterContext(NeoExtraKey.EKS_META_CONTEXT_NAME)
|
||||
visitor.getCurrentContext()
|
||||
.defineAttribute(NeoExtraKey.EKS_META_VERSION, NeoLangValue(config.version))
|
||||
.defineAttribute(NeoExtraKey.EKS_META_WITH_DEFAULT, NeoLangValue(config.withDefaultKeys))
|
||||
|
||||
// program
|
||||
visitor.onEnterContext(NeoExtraKey.EKS_META_PROGRAM)
|
||||
config.programNames.forEachIndexed { index, program ->
|
||||
visitor.getCurrentContext().defineAttribute(index.toString(), NeoLangValue(program))
|
||||
}
|
||||
visitor.onExitContext()
|
||||
|
||||
// key
|
||||
visitor.onEnterContext(NeoExtraKey.EKS_META_KEY)
|
||||
config.shortcutKeys.forEachIndexed { index, button ->
|
||||
if (button is TextButton) {
|
||||
visitor.onEnterContext(index.toString())
|
||||
visitor.getCurrentContext()
|
||||
.defineAttribute(NeoExtraKey.EKS_META_WITH_ENTER, NeoLangValue(button.withEnter))
|
||||
.defineAttribute(NeoExtraKey.EKS_META_DISPLAY, NeoLangValue(button.buttonKeys!!))
|
||||
.defineAttribute(NeoExtraKey.EKS_META_CODE, NeoLangValue(button.buttonKeys!!))
|
||||
visitor.onExitContext()
|
||||
}
|
||||
}
|
||||
visitor.onExitContext()
|
||||
|
||||
visitor.onFinish()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun parseOldConfig(source: BufferedReader): NeoExtraKey {
|
||||
val config = NeoExtraKey()
|
||||
var line: String? = source.readLine()
|
||||
|
||||
while (line != null) {
|
||||
line = line.trim().trimEnd()
|
||||
if (line.isEmpty() || line.startsWith("#")) {
|
||||
line = source.readLine()
|
||||
continue
|
||||
}
|
||||
|
||||
if (line.startsWith(NeoExtraKey.EKS_META_VERSION)) {
|
||||
parseHeader(line, config)
|
||||
} else if (line.startsWith(NeoExtraKey.EKS_META_PROGRAM)) {
|
||||
parseProgram(line, config)
|
||||
} else if (line.startsWith("define")) {
|
||||
parseKeyDefine(line, config)
|
||||
} else if (line.startsWith(NeoExtraKey.EKS_META_WITH_DEFAULT)) {
|
||||
parseWithDefault(line, config)
|
||||
}
|
||||
line = source.readLine()
|
||||
}
|
||||
|
||||
if (config.version < 0) {
|
||||
throw RuntimeException("Not a valid shortcut config file")
|
||||
}
|
||||
if (config.programNames.size == 0) {
|
||||
throw RuntimeException("At least one program name should be given")
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
private fun parseWithDefault(line: String, config: NeoExtraKey) {
|
||||
val value = line.substring(NeoExtraKey.EKS_META_WITH_DEFAULT.length).trim().trimEnd()
|
||||
config.withDefaultKeys = value == "true"
|
||||
}
|
||||
|
||||
private fun parseKeyDefine(line: String, config: NeoExtraKey) {
|
||||
val keyDefine = line.substring("define".length).trim().trimEnd()
|
||||
val keyValues = keyDefine.split(" ")
|
||||
if (keyValues.size < 2) {
|
||||
throw RuntimeException("Bad define")
|
||||
}
|
||||
|
||||
val buttonText = keyValues[0]
|
||||
val withEnter = keyValues[1] == "true"
|
||||
|
||||
config.shortcutKeys.add(TextButton(buttonText, withEnter))
|
||||
}
|
||||
|
||||
private fun parseProgram(line: String, config: NeoExtraKey) {
|
||||
val programNames = line.substring(NeoExtraKey.EKS_META_PROGRAM.length).trim().trimEnd()
|
||||
if (programNames.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
for (name in programNames.split(" ")) {
|
||||
config.programNames.add(name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseHeader(line: String, config: NeoExtraKey) {
|
||||
val version: Int
|
||||
val versionString = line.substring(NeoExtraKey.EKS_META_VERSION.length).trim().trimEnd()
|
||||
try {
|
||||
version = Integer.parseInt(versionString)
|
||||
} catch (e: NumberFormatException) {
|
||||
throw RuntimeException("Bad version '$versionString'")
|
||||
}
|
||||
|
||||
config.version = version
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
package io.neoterm.frontend.component.helper
|
||||
package io.neoterm.component
|
||||
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.component.config.ConfigureComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.component.NeoComponent
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.utils.NLog
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface ConfigFileBasedObject {
|
||||
@Throws(RuntimeException::class)
|
||||
fun onConfigLoaded(configVisitor: ConfigVisitor)
|
||||
}
|
||||
|
||||
abstract class ConfigFileBasedComponent<out T : ConfigFileBasedObject>(protected val baseDir: String) : NeoComponent {
|
||||
companion object {
|
||||
private val TAG = ConfigFileBasedComponent::class.java.simpleName
|
||||
@ -61,3 +61,4 @@ abstract class ConfigFileBasedComponent<out T : ConfigFileBasedObject>(protected
|
||||
|
||||
abstract fun onCreateComponentObject(configVisitor: ConfigVisitor): T
|
||||
}
|
||||
|
@ -3,16 +3,13 @@ package io.neoterm.component.extrakey
|
||||
import android.content.Context
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.App
|
||||
import io.neoterm.frontend.component.helper.ConfigFileBasedComponent
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.component.ConfigFileBasedComponent
|
||||
import io.neoterm.component.config.NeoTermPath
|
||||
import io.neoterm.frontend.session.view.extrakey.ExtraKeysView
|
||||
import io.neoterm.utils.NLog
|
||||
import io.neoterm.utils.extractAssetsDir
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ExtraKeyComponent : ConfigFileBasedComponent<NeoExtraKey>(NeoTermPath.EKS_PATH) {
|
||||
override val checkComponentFileWhenObtained
|
||||
get() = true
|
@ -1,16 +1,10 @@
|
||||
package io.neoterm.component.extrakey
|
||||
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.component.config.ConfigureComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.component.helper.ConfigFileBasedObject
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.frontend.terminal.extrakey.button.IExtraButton
|
||||
import io.neoterm.frontend.terminal.extrakey.button.TextButton
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.io.File
|
||||
import io.neoterm.component.ConfigFileBasedObject
|
||||
import io.neoterm.frontend.session.view.extrakey.ExtraKeysView
|
||||
import io.neoterm.frontend.session.view.extrakey.IExtraButton
|
||||
import io.neoterm.frontend.session.view.extrakey.TextButton
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -86,24 +80,4 @@ class NeoExtraKey : ConfigFileBasedObject {
|
||||
private fun getMetaByVisitor(visitor: ConfigVisitor, metaName: String): String? {
|
||||
return visitor.getStringValue(EKS_META_CONTEXT_PATH, metaName)
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun testLoadConfigure(file: File): Boolean {
|
||||
val loaderService = ComponentManager.getComponent<ConfigureComponent>()
|
||||
|
||||
val configure: NeoConfigureFile?
|
||||
try {
|
||||
configure = loaderService.newLoader(file).loadConfigure()
|
||||
if (configure == null) {
|
||||
throw RuntimeException("Parse configuration failed.")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
NLog.e("ExtraKey", "Failed to load extra key config: ${file.absolutePath}: ${e.localizedMessage}")
|
||||
return false
|
||||
}
|
||||
|
||||
val visitor = configure.getVisitor()
|
||||
onConfigLoaded(visitor)
|
||||
return true
|
||||
}
|
||||
}
|
@ -4,18 +4,15 @@ import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import io.neoterm.App
|
||||
import io.neoterm.R
|
||||
import io.neoterm.frontend.component.NeoComponent
|
||||
import io.neoterm.frontend.config.DefaultValues
|
||||
import io.neoterm.frontend.config.NeoPreference
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.component.NeoComponent
|
||||
import io.neoterm.component.config.DefaultValues
|
||||
import io.neoterm.component.config.NeoPreference
|
||||
import io.neoterm.component.config.NeoTermPath
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
import io.neoterm.frontend.session.view.extrakey.ExtraKeysView
|
||||
import io.neoterm.utils.extractAssetsDir
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class FontComponent : NeoComponent {
|
||||
private lateinit var DEFAULT_FONT: NeoFont
|
||||
private lateinit var fonts: MutableMap<String, NeoFont>
|
||||
@ -127,3 +124,4 @@ class FontComponent : NeoComponent {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,10 @@
|
||||
package io.neoterm.component.font
|
||||
|
||||
import android.graphics.Typeface
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
import io.neoterm.frontend.session.view.extrakey.ExtraKeysView
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoFont {
|
||||
private var fontFile: File? = null
|
||||
private var typeface: Typeface? = null
|
@ -1,21 +0,0 @@
|
||||
package io.neoterm.component.pm
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
enum class Architecture {
|
||||
ALL, ARM, AARCH64, X86, X86_64;
|
||||
|
||||
companion object {
|
||||
fun parse(arch: String): Architecture {
|
||||
return when (arch) {
|
||||
"arm" -> ARM
|
||||
"aarch64" -> AARCH64
|
||||
"x86" -> X86
|
||||
"x86_64" -> X86_64
|
||||
else -> ALL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package io.neoterm.component.pm;
|
||||
|
||||
import io.neoterm.frontend.component.NeoComponent;
|
||||
import io.neoterm.component.NeoComponent;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -1,54 +0,0 @@
|
||||
package io.neoterm.component.pm
|
||||
|
||||
import io.neoterm.App
|
||||
import io.neoterm.R
|
||||
import io.neoterm.framework.NeoTermDatabase
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class SourceManager internal constructor() {
|
||||
private val database = NeoTermDatabase.instance("sources")
|
||||
|
||||
init {
|
||||
if (database.findAll<Source>(Source::class.java).isEmpty()) {
|
||||
App.get().resources.getStringArray(R.array.pref_package_source_values)
|
||||
.forEach {
|
||||
database.saveBean(Source(it, "stable main", true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addSource(sourceUrl: String, repo: String, enabled: Boolean) {
|
||||
database.saveBean(Source(sourceUrl, repo, enabled))
|
||||
}
|
||||
|
||||
fun removeSource(sourceUrl: String) {
|
||||
database.deleteBeanByWhere(Source::class.java, "url == '$sourceUrl'")
|
||||
}
|
||||
|
||||
fun updateAll(sources: List<Source>) {
|
||||
database.dropAllTable()
|
||||
database.saveBeans(sources)
|
||||
}
|
||||
|
||||
fun getAllSources(): List<Source> {
|
||||
return database.findAll<Source>(Source::class.java)
|
||||
}
|
||||
|
||||
fun getEnabledSources(): List<Source> {
|
||||
return getAllSources().filter { it.enabled }
|
||||
}
|
||||
|
||||
fun getMainPackageSource(): String {
|
||||
return getEnabledSources()
|
||||
.map { it.repo }
|
||||
.singleOrNull { it.trim() == "stable main" }
|
||||
?: NeoTermPath.DEFAULT_MAIN_PACKAGE_SOURCE
|
||||
}
|
||||
|
||||
fun applyChanges() {
|
||||
database.vacuum()
|
||||
}
|
||||
}
|
@ -1,8 +1,20 @@
|
||||
package io.neoterm.component.pm
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
enum class Architecture {
|
||||
ALL, ARM, AARCH64, X86, X86_64;
|
||||
|
||||
companion object {
|
||||
fun parse(arch: String): Architecture {
|
||||
return when (arch) {
|
||||
"arm" -> ARM
|
||||
"aarch64" -> AARCH64
|
||||
"x86" -> X86
|
||||
"x86_64" -> X86_64
|
||||
else -> ALL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NeoPackageInfo {
|
||||
var packageName: String? = null
|
||||
@ -21,4 +33,3 @@ class NeoPackageInfo {
|
||||
var homePage: String? = null
|
||||
var description: String? = null
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
package io.neoterm.component.pm
|
||||
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.App
|
||||
import io.neoterm.R
|
||||
import io.neoterm.component.ComponentManager
|
||||
import io.neoterm.component.config.NeoTermPath
|
||||
import io.neoterm.framework.NeoTermDatabase
|
||||
import io.neoterm.utils.NLog
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object SourceHelper {
|
||||
fun syncSource() {
|
||||
val sourceManager = ComponentManager.getComponent<PackageComponent>().sourceManager
|
||||
@ -72,3 +72,49 @@ object SourceHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SourceManager internal constructor() {
|
||||
private val database = NeoTermDatabase.instance("sources")
|
||||
|
||||
init {
|
||||
if (database.findAll<Source>(Source::class.java).isEmpty()) {
|
||||
App.get().resources.getStringArray(R.array.pref_package_source_values)
|
||||
.forEach {
|
||||
database.saveBean(Source(it, "stable main", true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addSource(sourceUrl: String, repo: String, enabled: Boolean) {
|
||||
database.saveBean(Source(sourceUrl, repo, enabled))
|
||||
}
|
||||
|
||||
fun removeSource(sourceUrl: String) {
|
||||
database.deleteBeanByWhere(Source::class.java, "url == '$sourceUrl'")
|
||||
}
|
||||
|
||||
fun updateAll(sources: List<Source>) {
|
||||
database.dropAllTable()
|
||||
database.saveBeans(sources)
|
||||
}
|
||||
|
||||
fun getAllSources(): List<Source> {
|
||||
return database.findAll(Source::class.java)
|
||||
}
|
||||
|
||||
fun getEnabledSources(): List<Source> {
|
||||
return getAllSources().filter { it.enabled }
|
||||
}
|
||||
|
||||
fun getMainPackageSource(): String {
|
||||
return getEnabledSources()
|
||||
.map { it.repo }
|
||||
.singleOrNull { it.trim() == "stable main" }
|
||||
?: NeoTermPath.DEFAULT_MAIN_PACKAGE_SOURCE
|
||||
}
|
||||
|
||||
fun applyChanges() {
|
||||
database.vacuum()
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
package io.neoterm.component.profile
|
||||
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.frontend.component.helper.ConfigFileBasedComponent
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.component.ConfigFileBasedComponent
|
||||
import io.neoterm.component.config.NeoTermPath
|
||||
import io.neoterm.utils.NLog
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ProfileComponent : ConfigFileBasedComponent<NeoProfile>(NeoTermPath.PROFILE_PATH) {
|
||||
override val checkComponentFileWhenObtained
|
||||
get() = true
|
@ -1,21 +1,18 @@
|
||||
package io.neoterm.component.profile
|
||||
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.component.ComponentManager
|
||||
import io.neoterm.component.ConfigFileBasedObject
|
||||
import io.neoterm.component.codegen.CodeGenObject
|
||||
import io.neoterm.component.codegen.CodeGenParameter
|
||||
import io.neoterm.component.codegen.generators.NeoProfileGenerator
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenObject
|
||||
import io.neoterm.component.codegen.interfaces.CodeGenerator
|
||||
import io.neoterm.component.codegen.CodeGenerator
|
||||
import io.neoterm.component.codegen.NeoProfileGenerator
|
||||
import io.neoterm.component.config.ConfigureComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.component.helper.ConfigFileBasedObject
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.component.config.NeoConfigureFile
|
||||
import io.neoterm.utils.NLog
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
abstract class NeoProfile : CodeGenObject, ConfigFileBasedObject {
|
||||
companion object {
|
||||
private const val PROFILE_NAME = "name"
|
@ -4,18 +4,10 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import io.neoterm.Globals
|
||||
import io.neoterm.frontend.component.NeoComponent
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.session.shell.ShellParameter
|
||||
import io.neoterm.frontend.session.shell.ShellTermSession
|
||||
import io.neoterm.frontend.session.xorg.XParameter
|
||||
import io.neoterm.frontend.session.xorg.XSession
|
||||
import io.neoterm.frontend.session.xorg.client.XSessionData
|
||||
import io.neoterm.component.NeoComponent
|
||||
import io.neoterm.component.config.NeoTermPath
|
||||
import io.neoterm.utils.NLog
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class SessionComponent : NeoComponent {
|
||||
companion object {
|
||||
private var IS_LIBRARIES_LOADED = false
|
@ -1,13 +1,163 @@
|
||||
package io.neoterm.frontend.session.shell
|
||||
package io.neoterm.component.session
|
||||
|
||||
import android.content.Context
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.App
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.session.shell.client.TermSessionCallback
|
||||
import io.neoterm.bridge.SessionId
|
||||
import io.neoterm.component.ComponentManager
|
||||
import io.neoterm.component.colorscheme.ColorSchemeComponent
|
||||
import io.neoterm.component.config.DefaultValues
|
||||
import io.neoterm.component.config.NeoPreference
|
||||
import io.neoterm.component.config.NeoTermPath
|
||||
import io.neoterm.component.font.FontComponent
|
||||
import io.neoterm.component.profile.NeoProfile
|
||||
import io.neoterm.frontend.session.terminal.TermSessionCallback
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ShellParameter {
|
||||
var sessionId: SessionId? = null
|
||||
var executablePath: String? = null
|
||||
var arguments: Array<String>? = null
|
||||
var cwd: String? = null
|
||||
var initialCommand: String? = null
|
||||
var env: Array<Pair<String, String>>? = null
|
||||
var sessionCallback: TerminalSession.SessionChangedCallback? = null
|
||||
var systemShell: Boolean = false
|
||||
var shellProfile: ShellProfile? = null
|
||||
|
||||
fun executablePath(executablePath: String?): ShellParameter {
|
||||
this.executablePath = executablePath
|
||||
return this
|
||||
}
|
||||
|
||||
fun arguments(arguments: Array<String>?): ShellParameter {
|
||||
this.arguments = arguments
|
||||
return this
|
||||
}
|
||||
|
||||
fun currentWorkingDirectory(cwd: String?): ShellParameter {
|
||||
this.cwd = cwd
|
||||
return this
|
||||
}
|
||||
|
||||
fun initialCommand(initialCommand: String?): ShellParameter {
|
||||
this.initialCommand = initialCommand
|
||||
return this
|
||||
}
|
||||
|
||||
fun environment(env: Array<Pair<String, String>>?): ShellParameter {
|
||||
this.env = env
|
||||
return this
|
||||
}
|
||||
|
||||
fun callback(callback: TerminalSession.SessionChangedCallback?): ShellParameter {
|
||||
this.sessionCallback = callback
|
||||
return this
|
||||
}
|
||||
|
||||
fun systemShell(systemShell: Boolean): ShellParameter {
|
||||
this.systemShell = systemShell
|
||||
return this
|
||||
}
|
||||
|
||||
fun profile(shellProfile: ShellProfile): ShellParameter {
|
||||
this.shellProfile = shellProfile
|
||||
return this
|
||||
}
|
||||
|
||||
fun session(sessionId: SessionId?): ShellParameter {
|
||||
this.sessionId = sessionId
|
||||
return this
|
||||
}
|
||||
|
||||
fun willCreateNewSession(): Boolean {
|
||||
return sessionId?.equals(SessionId.NEW_SESSION) ?: true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ShellProfile : NeoProfile() {
|
||||
companion object {
|
||||
const val PROFILE_META_NAME = "profile-shell"
|
||||
|
||||
private const val LOGIN_SHELL = "login-shell"
|
||||
private const val INITIAL_COMMAND = "init-command"
|
||||
private const val BELL = "bell"
|
||||
private const val VIBRATE = "vibrate"
|
||||
private const val EXECVE_WRAPPER = "execve-wrapper"
|
||||
private const val SPECIAL_VOLUME_KEYS = "special-volume-keys"
|
||||
private const val AUTO_COMPLETION = "auto-completion"
|
||||
private const val BACK_KEY_TO_ESC = "back-key-esc"
|
||||
private const val EXTRA_KEYS = "extra-keys"
|
||||
private const val FONT = "font"
|
||||
private const val COLOR_SCHEME = "color-scheme"
|
||||
private const val WORD_BASED_IME = "word-based-ime"
|
||||
|
||||
fun create(): ShellProfile {
|
||||
return ShellProfile()
|
||||
}
|
||||
}
|
||||
|
||||
override val profileMetaName = PROFILE_META_NAME
|
||||
|
||||
var loginShell = DefaultValues.loginShell
|
||||
var initialCommand = DefaultValues.initialCommand
|
||||
|
||||
var enableBell = DefaultValues.enableBell
|
||||
var enableVibrate = DefaultValues.enableVibrate
|
||||
var enableExecveWrapper = DefaultValues.enableExecveWrapper
|
||||
var enableSpecialVolumeKeys = DefaultValues.enableSpecialVolumeKeys
|
||||
var enableAutoCompletion = DefaultValues.enableAutoCompletion
|
||||
var enableBackKeyToEscape = DefaultValues.enableBackButtonBeMappedToEscape
|
||||
var enableExtraKeys = DefaultValues.enableExtraKeys
|
||||
var enableWordBasedIme = DefaultValues.enableWordBasedIme
|
||||
|
||||
var profileFont: String
|
||||
var profileColorScheme: String
|
||||
|
||||
init {
|
||||
val fontComp = ComponentManager.getComponent<FontComponent>()
|
||||
val colorComp = ComponentManager.getComponent<ColorSchemeComponent>()
|
||||
|
||||
profileFont = fontComp.getCurrentFontName()
|
||||
profileColorScheme = colorComp.getCurrentColorSchemeName()
|
||||
|
||||
loginShell = NeoPreference.getLoginShellPath()
|
||||
initialCommand = NeoPreference.getInitialCommand()
|
||||
enableBell = NeoPreference.isBellEnabled()
|
||||
enableVibrate = NeoPreference.isVibrateEnabled()
|
||||
enableExecveWrapper = NeoPreference.isExecveWrapperEnabled()
|
||||
enableSpecialVolumeKeys = NeoPreference.isSpecialVolumeKeysEnabled()
|
||||
enableAutoCompletion = NeoPreference.isAutoCompletionEnabled()
|
||||
enableBackKeyToEscape = NeoPreference.isBackButtonBeMappedToEscapeEnabled()
|
||||
enableExtraKeys = NeoPreference.isExtraKeysEnabled()
|
||||
enableWordBasedIme = NeoPreference.isWordBasedImeEnabled()
|
||||
}
|
||||
|
||||
override fun onConfigLoaded(configVisitor: ConfigVisitor) {
|
||||
super.onConfigLoaded(configVisitor)
|
||||
loginShell = configVisitor.getProfileString(LOGIN_SHELL, loginShell)
|
||||
initialCommand = configVisitor.getProfileString(INITIAL_COMMAND, initialCommand)
|
||||
enableBell = configVisitor.getProfileBoolean(BELL, enableBell)
|
||||
enableVibrate = configVisitor.getProfileBoolean(VIBRATE, enableVibrate)
|
||||
enableExecveWrapper = configVisitor.getProfileBoolean(EXECVE_WRAPPER, enableExecveWrapper)
|
||||
enableSpecialVolumeKeys = configVisitor.getProfileBoolean(SPECIAL_VOLUME_KEYS, enableSpecialVolumeKeys)
|
||||
enableAutoCompletion = configVisitor.getProfileBoolean(AUTO_COMPLETION, enableAutoCompletion)
|
||||
enableBackKeyToEscape = configVisitor.getProfileBoolean(BACK_KEY_TO_ESC, enableBackKeyToEscape)
|
||||
enableExtraKeys = configVisitor.getProfileBoolean(EXTRA_KEYS, enableExtraKeys)
|
||||
enableWordBasedIme = configVisitor.getProfileBoolean(WORD_BASED_IME, enableWordBasedIme)
|
||||
profileFont = configVisitor.getProfileString(FONT, profileFont)
|
||||
profileColorScheme = configVisitor.getProfileString(COLOR_SCHEME, profileColorScheme)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.session.xorg
|
||||
package io.neoterm.component.session
|
||||
|
||||
import android.app.UiModeManager
|
||||
import android.content.Context
|
||||
@ -7,6 +7,7 @@ import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.inputmethodservice.Keyboard
|
||||
import android.inputmethodservice.KeyboardView
|
||||
import android.os.Build
|
||||
import android.os.SystemClock
|
||||
import android.text.InputType
|
||||
import android.view.*
|
||||
@ -15,14 +16,11 @@ import android.widget.EditText
|
||||
import android.widget.FrameLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import io.neoterm.*
|
||||
import io.neoterm.frontend.session.xorg.client.XSessionData
|
||||
import io.neoterm.xorg.NeoXorgViewClient
|
||||
import io.neoterm.xorg.R
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class XParameter
|
||||
|
||||
class XSession constructor(private val mActivity: AppCompatActivity, val mSessionData: XSessionData) :
|
||||
NeoXorgViewClient {
|
||||
@ -64,17 +62,11 @@ class XSession constructor(private val mActivity: AppCompatActivity, val mSessio
|
||||
}
|
||||
|
||||
override fun getContext() = mActivity
|
||||
|
||||
override fun isKeyboardWithoutTextInputShown() = mSessionData.keyboardWithoutTextInputShown
|
||||
|
||||
override fun isPaused() = mSessionData.isPaused
|
||||
|
||||
override fun runOnUiThread(runnable: Runnable?) = mActivity.runOnUiThread(runnable)
|
||||
|
||||
override fun getGLView() = mSessionData.glView
|
||||
|
||||
override fun getWindow() = mActivity.window!!
|
||||
|
||||
override fun getWindowManager() = mActivity.windowManager!!
|
||||
|
||||
override fun showScreenKeyboardWithoutTextInputField(keyboard: Int) {
|
||||
@ -244,7 +236,7 @@ class XSession constructor(private val mActivity: AppCompatActivity, val mSessio
|
||||
|
||||
val screenKeyboard = EditText(
|
||||
mActivity, null,
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
android.R.style.TextAppearance_Material_Widget_EditText
|
||||
else android.R.style.TextAppearance_Widget_EditText
|
||||
)
|
||||
@ -349,10 +341,10 @@ class XSession constructor(private val mActivity: AppCompatActivity, val mSessio
|
||||
|
||||
override fun setSystemMousePointerVisible(visible: Int) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
glView?.pointerIcon = android.view.PointerIcon.getSystemIcon(
|
||||
glView?.pointerIcon = PointerIcon.getSystemIcon(
|
||||
mActivity,
|
||||
if (visible == 0) android.view.PointerIcon.TYPE_NULL
|
||||
else android.view.PointerIcon.TYPE_DEFAULT
|
||||
if (visible == 0) PointerIcon.TYPE_NULL
|
||||
else PointerIcon.TYPE_DEFAULT
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -417,5 +409,18 @@ class XSession constructor(private val mActivity: AppCompatActivity, val mSessio
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class XSessionData {
|
||||
var videoLayout: FrameLayout? = null
|
||||
var audioThread: NeoAudioThread? = null
|
||||
var screenKeyboard: View? = null
|
||||
var glView: NeoGLView? = null
|
||||
|
||||
var isPaused = false
|
||||
var client: NeoXorgViewClient? = null
|
||||
|
||||
var keyboardWithoutTextInputShown = false
|
||||
var screenKeyboardHintMessage: String? = null
|
||||
var textInput = LinkedList<Int>()
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package io.neoterm.component.userscript
|
||||
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class UserScript(val scriptFile: File)
|
@ -3,17 +3,16 @@ package io.neoterm.component.userscript
|
||||
import android.content.Context
|
||||
import android.system.Os
|
||||
import io.neoterm.App
|
||||
import io.neoterm.frontend.component.NeoComponent
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.component.NeoComponent
|
||||
import io.neoterm.component.config.NeoTermPath
|
||||
import io.neoterm.utils.NLog
|
||||
import io.neoterm.utils.extractAssetsDir
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class UserScript(val scriptFile: File)
|
||||
|
||||
class UserScriptComponent : NeoComponent {
|
||||
private var userScripts = listOf<UserScript>()
|
||||
var userScripts = listOf<UserScript>()
|
||||
private val scriptDir = File(NeoTermPath.USER_SCRIPT_PATH)
|
||||
|
||||
override fun onServiceInit() = checkForFiles()
|
@ -9,7 +9,7 @@ import io.neoterm.App;
|
||||
import io.neoterm.framework.database.*;
|
||||
import io.neoterm.framework.database.bean.TableInfo;
|
||||
import io.neoterm.framework.reflection.Reflect;
|
||||
import io.neoterm.frontend.logging.NLog;
|
||||
import io.neoterm.utils.NLog;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.completion.view
|
||||
package io.neoterm.frontend.completion
|
||||
|
||||
import android.content.Context
|
||||
import android.view.Gravity
|
||||
@ -11,11 +11,11 @@ import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalColors
|
||||
import io.neoterm.component.ComponentManager
|
||||
import io.neoterm.component.colorscheme.ColorSchemeComponent
|
||||
import io.neoterm.frontend.completion.listener.OnCandidateSelectedListener
|
||||
import io.neoterm.frontend.completion.model.CompletionCandidate
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.component.completion.CompletionCandidate
|
||||
import io.neoterm.component.completion.OnCandidateSelectedListener
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -41,14 +41,13 @@ class CandidatePopupWindow(val context: Context) {
|
||||
// Ensure that the popup window will not cover the IME.
|
||||
val rootView = popWindow.contentView
|
||||
if (rootView is MaxHeightView) {
|
||||
val maxHeight = terminalView.height
|
||||
rootView.setMaxHeight(maxHeight)
|
||||
rootView.maxHeight = terminalView.height
|
||||
}
|
||||
|
||||
popWindow.showAtLocation(
|
||||
terminalView, Gravity.BOTTOM.and(Gravity.START),
|
||||
terminalView.cursorAbsoluteX,
|
||||
terminalView.cursorAbsoluteY
|
||||
terminalView.cursorAbsoluteY,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -69,12 +68,12 @@ class CandidatePopupWindow(val context: Context) {
|
||||
val listView = contentView.findViewById<ListView>(R.id.popup_complete_candidate_list)
|
||||
candidateAdapter = CandidateAdapter(this)
|
||||
listView.adapter = candidateAdapter
|
||||
listView.setOnItemClickListener({ _, _, position, _ ->
|
||||
listView.setOnItemClickListener { _, _, position, _ ->
|
||||
val selectedItem = candidates?.get(position)
|
||||
if (selectedItem != null) {
|
||||
onCandidateSelectedListener?.onCandidateSelected(selectedItem)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
candidateListView = listView
|
||||
popupWindow.contentView = contentView
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.completion.view
|
||||
package io.neoterm.frontend.completion
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
@ -6,18 +6,11 @@ import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
|
||||
class MaxHeightView : LinearLayout {
|
||||
var maxHeight = -1
|
||||
|
||||
private var maxHeight = -1
|
||||
|
||||
constructor(context: Context) : super(context) {}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}
|
||||
|
||||
fun setMaxHeight(maxHeight: Int) {
|
||||
this.maxHeight = maxHeight
|
||||
}
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
var finalHeightMeasureSpec = heightMeasureSpec
|
@ -1,25 +0,0 @@
|
||||
package io.neoterm.frontend.completion
|
||||
|
||||
import io.neoterm.frontend.completion.listener.MarkScoreListener
|
||||
import io.neoterm.frontend.completion.provider.ICandidateProvider
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ProviderDetector(val providers: List<ICandidateProvider>) : MarkScoreListener {
|
||||
private var detectedProvider: ICandidateProvider? = null
|
||||
|
||||
override fun onMarkScore(score: Int) {
|
||||
// TODO: Save provider score
|
||||
}
|
||||
|
||||
fun detectBest(): ICandidateProvider? {
|
||||
// TODO: detect best
|
||||
detectedProvider = if (providers.isEmpty())
|
||||
null
|
||||
else
|
||||
providers[0]
|
||||
|
||||
return detectedProvider
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package io.neoterm.frontend.completion.listener
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
interface MarkScoreListener {
|
||||
fun onMarkScore(score: Int)
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package io.neoterm.frontend.completion.listener
|
||||
|
||||
/**
|
||||
* @author Kiva
|
||||
* *
|
||||
* @version 1.0
|
||||
*/
|
||||
interface OnAutoCompleteListener {
|
||||
fun onCompletionRequired(newText: String?)
|
||||
|
||||
fun onKeyCode(keyCode: Int, keyMod: Int)
|
||||
|
||||
fun onCleanUp()
|
||||
|
||||
fun onFinishCompletion(): Boolean
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package io.neoterm.frontend.completion.listener
|
||||
|
||||
import io.neoterm.frontend.completion.model.CompletionCandidate
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface OnCandidateSelectedListener {
|
||||
fun onCandidateSelected(candidate: CompletionCandidate)
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package io.neoterm.frontend.completion.model
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class CompletionCandidate(var completeString: String) {
|
||||
var displayName: String = completeString
|
||||
var description: String? = null
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package io.neoterm.frontend.completion.provider
|
||||
|
||||
import io.neoterm.frontend.completion.model.CompletionCandidate
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
interface ICandidateProvider {
|
||||
val providerName: String
|
||||
|
||||
fun provideCandidates(text: String): List<CompletionCandidate>?
|
||||
|
||||
fun canComplete(text: String): Boolean
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package io.neoterm.frontend.component
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ComponentDuplicateException(serviceName: String) : RuntimeException("Service $serviceName duplicate")
|
@ -1,7 +0,0 @@
|
||||
package io.neoterm.frontend.component
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ComponentNotFoundException(serviceName: String) : RuntimeException("Component `$serviceName' not found") {
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package io.neoterm.frontend.component
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface NeoComponent {
|
||||
fun onServiceInit()
|
||||
fun onServiceDestroy()
|
||||
fun onServiceObtained()
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package io.neoterm.frontend.component.helper
|
||||
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface ConfigFileBasedObject {
|
||||
@Throws(RuntimeException::class)
|
||||
fun onConfigLoaded(configVisitor: ConfigVisitor)
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package io.neoterm.frontend.config
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object DefaultValues {
|
||||
const val fontSize = 30
|
||||
|
||||
const val enableBell = false
|
||||
const val enableVibrate = false
|
||||
const val enableExecveWrapper = true
|
||||
const val enableAutoCompletion = false
|
||||
const val enableFullScreen = false
|
||||
const val enableAutoHideToolbar = false
|
||||
const val enableSwitchNextTab = false
|
||||
const val enableExtraKeys = true
|
||||
const val enableExplicitExtraKeysWeight = false
|
||||
const val enableBackButtonBeMappedToEscape = false
|
||||
const val enableSpecialVolumeKeys = false
|
||||
const val enableWordBasedIme = false
|
||||
|
||||
const val loginShell = "bash"
|
||||
const val initialCommand = ""
|
||||
const val defaultFont = "SourceCodePro"
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package io.neoterm.frontend.config
|
||||
|
||||
import io.neolang.parser.NeoLangParser
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class NeoConfigureFile(val configureFile: File) {
|
||||
private val configParser = NeoLangParser()
|
||||
open protected var configVisitor: ConfigVisitor? = null
|
||||
|
||||
fun getVisitor() = configVisitor ?: throw IllegalStateException("Configure file not loaded or parse failed.")
|
||||
|
||||
open fun parseConfigure() = kotlin.runCatching {
|
||||
val programCode = String(Files.readAllBytes(configureFile.toPath()))
|
||||
configParser.setInputSource(programCode)
|
||||
|
||||
val ast = configParser.parse()
|
||||
val astVisitor = ast.visit().getVisitor(ConfigVisitor::class.java) ?: return false
|
||||
astVisitor.start()
|
||||
configVisitor = astVisitor.getCallback()
|
||||
}.isSuccess
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package io.neoterm.frontend.floating
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.TerminalViewClient
|
||||
import io.neoterm.utils.Terminals
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class WindowTermView(val context: Context) {
|
||||
@SuppressLint("InflateParams")
|
||||
var rootView: View = LayoutInflater.from(context).inflate(R.layout.ui_term_dialog, null, false)
|
||||
private set
|
||||
var terminalView: TerminalView = rootView.findViewById<TerminalView>(R.id.terminal_view_dialog)
|
||||
private set
|
||||
|
||||
init {
|
||||
Terminals.setupTerminalView(terminalView)
|
||||
}
|
||||
|
||||
fun setTerminalViewClient(terminalViewClient: TerminalViewClient?) {
|
||||
terminalView.setTerminalViewClient(terminalViewClient)
|
||||
}
|
||||
|
||||
fun attachSession(terminalSession: TerminalSession?) {
|
||||
terminalView.attachSession(terminalSession)
|
||||
}
|
||||
|
||||
fun setInputMethodEnabled(enabled: Boolean) {
|
||||
terminalView.isFocusable = enabled
|
||||
terminalView.isFocusableInTouchMode = enabled
|
||||
}
|
||||
}
|
@ -1,21 +1,23 @@
|
||||
package io.neoterm.frontend.floating
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.frontend.session.shell.ShellParameter
|
||||
import io.neoterm.frontend.session.shell.ShellTermSession
|
||||
import io.neoterm.frontend.session.shell.client.BasicSessionCallback
|
||||
import io.neoterm.frontend.session.shell.client.BasicViewClient
|
||||
import io.neoterm.component.session.ShellParameter
|
||||
import io.neoterm.component.session.ShellTermSession
|
||||
import io.neoterm.frontend.session.terminal.BasicSessionCallback
|
||||
import io.neoterm.frontend.session.terminal.BasicViewClient
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
import io.neoterm.frontend.session.view.TerminalViewClient
|
||||
import io.neoterm.utils.Terminals
|
||||
|
||||
typealias DialogSessionFinished = (TerminalDialog, TerminalSession?) -> Unit
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class TerminalDialog(val context: Context) {
|
||||
private val termWindowView = WindowTermView(context)
|
||||
private val terminalSessionCallback: BasicSessionCallback
|
||||
@ -93,3 +95,28 @@ class TerminalDialog(val context: Context) {
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
class WindowTermView(val context: Context) {
|
||||
@SuppressLint("InflateParams")
|
||||
var rootView: View = LayoutInflater.from(context).inflate(R.layout.ui_term_dialog, null, false)
|
||||
private set
|
||||
var terminalView: TerminalView = rootView.findViewById<TerminalView>(R.id.terminal_view_dialog)
|
||||
private set
|
||||
|
||||
init {
|
||||
Terminals.setupTerminalView(terminalView)
|
||||
}
|
||||
|
||||
fun setTerminalViewClient(terminalViewClient: TerminalViewClient?) {
|
||||
terminalView.setTerminalViewClient(terminalViewClient)
|
||||
}
|
||||
|
||||
fun attachSession(terminalSession: TerminalSession?) {
|
||||
terminalView.attachSession(terminalSession)
|
||||
}
|
||||
|
||||
fun setInputMethodEnabled(enabled: Boolean) {
|
||||
terminalView.isFocusable = enabled
|
||||
terminalView.isFocusableInTouchMode = enabled
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell
|
||||
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.bridge.SessionId
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ShellParameter {
|
||||
var sessionId: SessionId? = null
|
||||
var executablePath: String? = null
|
||||
var arguments: Array<String>? = null
|
||||
var cwd: String? = null
|
||||
var initialCommand: String? = null
|
||||
var env: Array<Pair<String, String>>? = null
|
||||
var sessionCallback: TerminalSession.SessionChangedCallback? = null
|
||||
var systemShell: Boolean = false
|
||||
var shellProfile: ShellProfile? = null
|
||||
|
||||
fun executablePath(executablePath: String?): ShellParameter {
|
||||
this.executablePath = executablePath
|
||||
return this
|
||||
}
|
||||
|
||||
fun arguments(arguments: Array<String>?): ShellParameter {
|
||||
this.arguments = arguments
|
||||
return this
|
||||
}
|
||||
|
||||
fun currentWorkingDirectory(cwd: String?): ShellParameter {
|
||||
this.cwd = cwd
|
||||
return this
|
||||
}
|
||||
|
||||
fun initialCommand(initialCommand: String?): ShellParameter {
|
||||
this.initialCommand = initialCommand
|
||||
return this
|
||||
}
|
||||
|
||||
fun environment(env: Array<Pair<String, String>>?): ShellParameter {
|
||||
this.env = env
|
||||
return this
|
||||
}
|
||||
|
||||
fun callback(callback: TerminalSession.SessionChangedCallback?): ShellParameter {
|
||||
this.sessionCallback = callback
|
||||
return this
|
||||
}
|
||||
|
||||
fun systemShell(systemShell: Boolean): ShellParameter {
|
||||
this.systemShell = systemShell
|
||||
return this
|
||||
}
|
||||
|
||||
fun profile(shellProfile: ShellProfile): ShellParameter {
|
||||
this.shellProfile = shellProfile
|
||||
return this
|
||||
}
|
||||
|
||||
fun session(sessionId: SessionId?): ShellParameter {
|
||||
this.sessionId = sessionId
|
||||
return this
|
||||
}
|
||||
|
||||
fun willCreateNewSession(): Boolean {
|
||||
return sessionId?.equals(SessionId.NEW_SESSION) ?: true
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell
|
||||
|
||||
import io.neolang.visitor.ConfigVisitor
|
||||
import io.neoterm.component.colorscheme.ColorSchemeComponent
|
||||
import io.neoterm.component.font.FontComponent
|
||||
import io.neoterm.component.profile.NeoProfile
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.config.DefaultValues
|
||||
import io.neoterm.frontend.config.NeoPreference
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ShellProfile : NeoProfile() {
|
||||
companion object {
|
||||
const val PROFILE_META_NAME = "profile-shell"
|
||||
|
||||
private const val LOGIN_SHELL = "login-shell"
|
||||
private const val INITIAL_COMMAND = "init-command"
|
||||
private const val BELL = "bell"
|
||||
private const val VIBRATE = "vibrate"
|
||||
private const val EXECVE_WRAPPER = "execve-wrapper"
|
||||
private const val SPECIAL_VOLUME_KEYS = "special-volume-keys"
|
||||
private const val AUTO_COMPLETION = "auto-completion"
|
||||
private const val BACK_KEY_TO_ESC = "back-key-esc"
|
||||
private const val EXTRA_KEYS = "extra-keys"
|
||||
private const val FONT = "font"
|
||||
private const val COLOR_SCHEME = "color-scheme"
|
||||
private const val WORD_BASED_IME = "word-based-ime"
|
||||
|
||||
fun create(): ShellProfile {
|
||||
return ShellProfile()
|
||||
}
|
||||
}
|
||||
|
||||
override val profileMetaName = PROFILE_META_NAME
|
||||
|
||||
var loginShell = DefaultValues.loginShell
|
||||
var initialCommand = DefaultValues.initialCommand
|
||||
|
||||
var enableBell = DefaultValues.enableBell
|
||||
var enableVibrate = DefaultValues.enableVibrate
|
||||
var enableExecveWrapper = DefaultValues.enableExecveWrapper
|
||||
var enableSpecialVolumeKeys = DefaultValues.enableSpecialVolumeKeys
|
||||
var enableAutoCompletion = DefaultValues.enableAutoCompletion
|
||||
var enableBackKeyToEscape = DefaultValues.enableBackButtonBeMappedToEscape
|
||||
var enableExtraKeys = DefaultValues.enableExtraKeys
|
||||
var enableWordBasedIme = DefaultValues.enableWordBasedIme
|
||||
|
||||
var profileFont: String
|
||||
var profileColorScheme: String
|
||||
|
||||
init {
|
||||
val fontComp = ComponentManager.getComponent<FontComponent>()
|
||||
val colorComp = ComponentManager.getComponent<ColorSchemeComponent>()
|
||||
|
||||
profileFont = fontComp.getCurrentFontName()
|
||||
profileColorScheme = colorComp.getCurrentColorSchemeName()
|
||||
|
||||
loginShell = NeoPreference.getLoginShellPath()
|
||||
initialCommand = NeoPreference.getInitialCommand()
|
||||
enableBell = NeoPreference.isBellEnabled()
|
||||
enableVibrate = NeoPreference.isVibrateEnabled()
|
||||
enableExecveWrapper = NeoPreference.isExecveWrapperEnabled()
|
||||
enableSpecialVolumeKeys = NeoPreference.isSpecialVolumeKeysEnabled()
|
||||
enableAutoCompletion = NeoPreference.isAutoCompletionEnabled()
|
||||
enableBackKeyToEscape = NeoPreference.isBackButtonBeMappedToEscapeEnabled()
|
||||
enableExtraKeys = NeoPreference.isExtraKeysEnabled()
|
||||
enableWordBasedIme = NeoPreference.isWordBasedImeEnabled()
|
||||
}
|
||||
|
||||
override fun onConfigLoaded(configVisitor: ConfigVisitor) {
|
||||
super.onConfigLoaded(configVisitor)
|
||||
loginShell = configVisitor.getProfileString(LOGIN_SHELL, loginShell)
|
||||
initialCommand = configVisitor.getProfileString(INITIAL_COMMAND, initialCommand)
|
||||
enableBell = configVisitor.getProfileBoolean(BELL, enableBell)
|
||||
enableVibrate = configVisitor.getProfileBoolean(VIBRATE, enableVibrate)
|
||||
enableExecveWrapper = configVisitor.getProfileBoolean(EXECVE_WRAPPER, enableExecveWrapper)
|
||||
enableSpecialVolumeKeys = configVisitor.getProfileBoolean(SPECIAL_VOLUME_KEYS, enableSpecialVolumeKeys)
|
||||
enableAutoCompletion = configVisitor.getProfileBoolean(AUTO_COMPLETION, enableAutoCompletion)
|
||||
enableBackKeyToEscape = configVisitor.getProfileBoolean(BACK_KEY_TO_ESC, enableBackKeyToEscape)
|
||||
enableExtraKeys = configVisitor.getProfileBoolean(EXTRA_KEYS, enableExtraKeys)
|
||||
enableWordBasedIme = configVisitor.getProfileBoolean(WORD_BASED_IME, enableWordBasedIme)
|
||||
profileFont = configVisitor.getProfileString(FONT, profileFont)
|
||||
profileColorScheme = configVisitor.getProfileString(COLOR_SCHEME, profileColorScheme)
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client
|
||||
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class BasicSessionCallback(var terminalView: TerminalView) : TerminalSession.SessionChangedCallback {
|
||||
override fun onTextChanged(changedSession: TerminalSession?) {
|
||||
if (changedSession != null) {
|
||||
terminalView.onScreenUpdated()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTitleChanged(changedSession: TerminalSession?) {
|
||||
}
|
||||
|
||||
override fun onSessionFinished(finishedSession: TerminalSession?) {
|
||||
}
|
||||
|
||||
override fun onClipboardText(session: TerminalSession?, text: String?) {
|
||||
}
|
||||
|
||||
override fun onBell(session: TerminalSession?) {
|
||||
}
|
||||
|
||||
override fun onColorsChanged(session: TerminalSession?) {
|
||||
if (session != null) {
|
||||
terminalView.onScreenUpdated()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client
|
||||
|
||||
import android.content.Context
|
||||
import android.media.SoundPool
|
||||
import android.os.Vibrator
|
||||
import io.neoterm.R
|
||||
import io.neoterm.frontend.session.shell.ShellTermSession
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class BellController constructor() {
|
||||
companion object {
|
||||
private val BELL_DELAY_MS = 100
|
||||
}
|
||||
|
||||
private var bellId: Int = 0
|
||||
private var soundPool: SoundPool? = null
|
||||
private var lastBellTime = 0L
|
||||
|
||||
fun bellOrVibrate(context: Context, session: ShellTermSession) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (currentTime - lastBellTime < BELL_DELAY_MS) {
|
||||
return
|
||||
}
|
||||
lastBellTime = currentTime
|
||||
|
||||
if (session.shellProfile.enableBell) {
|
||||
if (soundPool == null) {
|
||||
soundPool = SoundPool.Builder().setMaxStreams(1).build()
|
||||
bellId = soundPool!!.load(context, R.raw.bell, 1)
|
||||
}
|
||||
soundPool?.play(bellId, 1f, 1f, 0, 0, 1f)
|
||||
}
|
||||
|
||||
if (session.shellProfile.enableVibrate) {
|
||||
val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
vibrator.vibrate(100)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client
|
||||
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import io.neoterm.BuildConfig
|
||||
import io.neoterm.frontend.completion.CompletionManager
|
||||
import io.neoterm.frontend.completion.listener.OnAutoCompleteListener
|
||||
import io.neoterm.frontend.completion.listener.OnCandidateSelectedListener
|
||||
import io.neoterm.frontend.completion.model.CompletionCandidate
|
||||
import io.neoterm.frontend.completion.model.CompletionResult
|
||||
import io.neoterm.frontend.completion.view.CandidatePopupWindow
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class TermCompleteListener(var terminalView: TerminalView?) : OnAutoCompleteListener, OnCandidateSelectedListener {
|
||||
private val inputStack = Stack<Char>()
|
||||
private var popupWindow: CandidatePopupWindow? = null
|
||||
private var lastCompletedIndex = 0
|
||||
|
||||
override fun onKeyCode(keyCode: Int, keyMod: Int) {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_DEL -> {
|
||||
popChar()
|
||||
fixLastCompletedIndex()
|
||||
triggerCompletion()
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_ENTER -> {
|
||||
clearChars()
|
||||
popupWindow?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fixLastCompletedIndex() {
|
||||
val currentText = getCurrentEditingText()
|
||||
lastCompletedIndex = minOf(lastCompletedIndex, currentText.length - 1)
|
||||
}
|
||||
|
||||
override fun onCompletionRequired(newText: String?) {
|
||||
if (newText == null || newText.isEmpty()) {
|
||||
return
|
||||
}
|
||||
pushString(newText)
|
||||
triggerCompletion()
|
||||
}
|
||||
|
||||
override fun onCleanUp() {
|
||||
popupWindow?.dismiss()
|
||||
popupWindow?.cleanup()
|
||||
popupWindow = null
|
||||
terminalView = null
|
||||
}
|
||||
|
||||
override fun onFinishCompletion(): Boolean {
|
||||
val popWindow = popupWindow ?: return false
|
||||
|
||||
if (popWindow.isShowing()) {
|
||||
popWindow.dismiss()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onCandidateSelected(candidate: CompletionCandidate) {
|
||||
val session = terminalView?.currentSession ?: return
|
||||
val textNeedCompletion = getCurrentEditingText().substring(lastCompletedIndex + 1)
|
||||
val newText = candidate.completeString
|
||||
|
||||
val deleteLength = newText.indexOf(textNeedCompletion) + textNeedCompletion.length
|
||||
if (deleteLength > 0) {
|
||||
for (i in 0 until deleteLength) {
|
||||
session.write("\b")
|
||||
popChar()
|
||||
}
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e(
|
||||
"NeoTerm-AC", "currentEditing: $textNeedCompletion, " +
|
||||
"deleteLength: $deleteLength, completeString: $newText"
|
||||
)
|
||||
}
|
||||
|
||||
pushString(newText)
|
||||
session.write(newText)
|
||||
// Trigger next completion
|
||||
lastCompletedIndex = inputStack.size
|
||||
triggerCompletion()
|
||||
}
|
||||
|
||||
private fun triggerCompletion() {
|
||||
val text = getCurrentEditingText()
|
||||
if (text.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val result = CompletionManager.tryCompleteFor(text)
|
||||
if (!result.hasResult()) {
|
||||
// A provider accepted the task
|
||||
// But no candidates are provided
|
||||
// Give it zero angrily!
|
||||
result.markScore(0)
|
||||
onFinishCompletion()
|
||||
return
|
||||
}
|
||||
showAutoCompleteCandidates(result)
|
||||
}
|
||||
|
||||
private fun showAutoCompleteCandidates(result: CompletionResult) {
|
||||
val termView = terminalView
|
||||
var popWindow = popupWindow
|
||||
|
||||
if (termView == null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (popWindow == null) {
|
||||
popWindow = CandidatePopupWindow(termView.context)
|
||||
popWindow.onCandidateSelectedListener = this
|
||||
this.popupWindow = popWindow
|
||||
}
|
||||
|
||||
popWindow.candidates = result.candidates
|
||||
popWindow.show(termView)
|
||||
}
|
||||
|
||||
private fun getCurrentEditingText(): String {
|
||||
val builder = StringBuilder()
|
||||
val size = inputStack.size
|
||||
var start = inputStack.lastIndexOf(' ')
|
||||
if (start < 0) {
|
||||
// Yes, it is -1, we will do `start + 1` below.
|
||||
start = -1
|
||||
}
|
||||
|
||||
IntRange(start + 1, size - 1)
|
||||
.map { inputStack[it] }
|
||||
.takeWhile { !(it == 0.toChar() || it == ' ') }
|
||||
.forEach { builder.append(it) }
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private fun clearChars() {
|
||||
inputStack.clear()
|
||||
lastCompletedIndex = 0
|
||||
}
|
||||
|
||||
private fun popChar() {
|
||||
if (inputStack.isNotEmpty()) {
|
||||
inputStack.pop()
|
||||
}
|
||||
}
|
||||
|
||||
private fun pushString(string: String) {
|
||||
string.toCharArray().forEach { pushChar(it) }
|
||||
}
|
||||
|
||||
private fun pushChar(char: Char) {
|
||||
inputStack.push(char)
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.frontend.session.shell.ShellTermSession
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class TermSessionCallback : TerminalSession.SessionChangedCallback {
|
||||
var termSessionData: TermSessionData? = null
|
||||
|
||||
var bellController: BellController? = null
|
||||
|
||||
override fun onTextChanged(changedSession: TerminalSession?) {
|
||||
termSessionData?.termView?.onScreenUpdated()
|
||||
}
|
||||
|
||||
override fun onTitleChanged(changedSession: TerminalSession?) {
|
||||
if (changedSession?.title != null) {
|
||||
termSessionData?.termUI?.requireUpdateTitle(changedSession.title)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSessionFinished(finishedSession: TerminalSession?) {
|
||||
termSessionData?.termUI?.requireOnSessionFinished()
|
||||
}
|
||||
|
||||
override fun onClipboardText(session: TerminalSession?, text: String?) {
|
||||
val termView = termSessionData?.termView
|
||||
if (termView != null) {
|
||||
val clipboard = termView.context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard.primaryClip = ClipData.newPlainText("", text)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBell(session: TerminalSession?) {
|
||||
val termView = termSessionData?.termView ?: return
|
||||
val shellSession = session as ShellTermSession
|
||||
|
||||
if (bellController == null) {
|
||||
bellController = BellController()
|
||||
}
|
||||
|
||||
bellController?.bellOrVibrate(termView.context, shellSession)
|
||||
}
|
||||
|
||||
override fun onColorsChanged(session: TerminalSession?) {
|
||||
val termView = termSessionData?.termView
|
||||
if (session != null && termView != null) {
|
||||
termView.onScreenUpdated()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface TermUiPresenter {
|
||||
fun requireClose()
|
||||
fun requireToggleFullScreen()
|
||||
fun requirePaste()
|
||||
fun requireUpdateTitle(title: String?)
|
||||
fun requireOnSessionFinished()
|
||||
fun requireHideIme()
|
||||
fun requireFinishAutoCompletion(): Boolean
|
||||
fun requireCreateNew()
|
||||
fun requireSwitchToPrevious()
|
||||
fun requireSwitchToNext()
|
||||
fun requireSwitchTo(index: Int)
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client.event
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class CreateNewSessionEvent
|
@ -1,6 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client.event
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class SwitchIndexedSessionEvent(val index: Int)
|
@ -1,6 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client.event
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class SwitchSessionEvent(val toNext: Boolean)
|
@ -1,9 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client.event
|
||||
|
||||
import io.neoterm.ui.term.tab.TermTab
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
class TabCloseEvent(var termTab: TermTab)
|
@ -1,6 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client.event
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class TitleChangedEvent(val title: String)
|
@ -1,6 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client.event
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ToggleFullScreenEvent()
|
@ -1,6 +0,0 @@
|
||||
package io.neoterm.frontend.session.shell.client.event
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ToggleImeEvent
|
@ -1,15 +1,12 @@
|
||||
package io.neoterm.frontend.session.shell.client
|
||||
package io.neoterm.frontend.session.terminal
|
||||
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.frontend.completion.listener.OnAutoCompleteListener
|
||||
import io.neoterm.frontend.session.shell.ShellProfile
|
||||
import io.neoterm.frontend.session.shell.ShellTermSession
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.extrakey.ExtraKeysView
|
||||
import io.neoterm.component.completion.OnAutoCompleteListener
|
||||
import io.neoterm.component.session.ShellProfile
|
||||
import io.neoterm.component.session.ShellTermSession
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
import io.neoterm.frontend.session.view.extrakey.ExtraKeysView
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class TermSessionData {
|
||||
var termSession: TerminalSession? = null
|
||||
var sessionCallback: TermSessionCallback? = null
|
||||
@ -59,3 +56,17 @@ class TermSessionData {
|
||||
this.extraKeysView = eks
|
||||
}
|
||||
}
|
||||
|
||||
interface TermUiPresenter {
|
||||
fun requireClose()
|
||||
fun requireToggleFullScreen()
|
||||
fun requirePaste()
|
||||
fun requireUpdateTitle(title: String?)
|
||||
fun requireOnSessionFinished()
|
||||
fun requireHideIme()
|
||||
fun requireFinishAutoCompletion(): Boolean
|
||||
fun requireCreateNew()
|
||||
fun requireSwitchToPrevious()
|
||||
fun requireSwitchToNext()
|
||||
fun requireSwitchTo(index: Int)
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package io.neoterm.frontend.session.terminal
|
||||
|
||||
import io.neoterm.ui.term.TermTab
|
||||
|
||||
class CreateNewSessionEvent
|
||||
class SwitchIndexedSessionEvent(val index: Int)
|
||||
class SwitchSessionEvent(val toNext: Boolean)
|
||||
class TabCloseEvent(val termTab: TermTab)
|
||||
class TitleChangedEvent(val title: String)
|
||||
class ToggleFullScreenEvent
|
||||
class ToggleImeEvent
|
@ -1,17 +1,40 @@
|
||||
package io.neoterm.frontend.session.shell.client
|
||||
package io.neoterm.frontend.session.terminal
|
||||
|
||||
import android.content.Context
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.frontend.config.NeoPreference
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.TerminalViewClient
|
||||
import io.neoterm.component.config.NeoPreference
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
import io.neoterm.frontend.session.view.TerminalViewClient
|
||||
|
||||
open class BasicSessionCallback(var terminalView: TerminalView) : TerminalSession.SessionChangedCallback {
|
||||
override fun onTextChanged(changedSession: TerminalSession?) {
|
||||
if (changedSession != null) {
|
||||
terminalView.onScreenUpdated()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTitleChanged(changedSession: TerminalSession?) {
|
||||
}
|
||||
|
||||
override fun onSessionFinished(finishedSession: TerminalSession?) {
|
||||
}
|
||||
|
||||
override fun onClipboardText(session: TerminalSession?, text: String?) {
|
||||
}
|
||||
|
||||
override fun onBell(session: TerminalSession?) {
|
||||
}
|
||||
|
||||
override fun onColorsChanged(session: TerminalSession?) {
|
||||
if (session != null) {
|
||||
terminalView.onScreenUpdated()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class BasicViewClient(val terminalView: TerminalView) : TerminalViewClient {
|
||||
override fun onScale(scale: Float): Float {
|
||||
if (scale < 0.9f || scale > 1.1f) {
|
@ -1,20 +1,30 @@
|
||||
package io.neoterm.frontend.session.shell.client
|
||||
package io.neoterm.frontend.session.terminal
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.media.AudioManager
|
||||
import android.media.SoundPool
|
||||
import android.os.Vibrator
|
||||
import android.util.Log
|
||||
import android.view.InputDevice
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import io.neoterm.BuildConfig
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.KeyHandler
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.component.ComponentManager
|
||||
import io.neoterm.component.completion.*
|
||||
import io.neoterm.component.config.NeoPreference
|
||||
import io.neoterm.component.extrakey.ExtraKeyComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.config.NeoPreference
|
||||
import io.neoterm.frontend.session.shell.ShellTermSession
|
||||
import io.neoterm.frontend.terminal.TerminalViewClient
|
||||
|
||||
import io.neoterm.component.session.ShellTermSession
|
||||
import io.neoterm.frontend.completion.CandidatePopupWindow
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
import io.neoterm.frontend.session.view.TerminalViewClient
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
@ -268,3 +278,233 @@ class TermViewClient(val context: Context) : TerminalViewClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class TermSessionCallback : TerminalSession.SessionChangedCallback {
|
||||
var termSessionData: TermSessionData? = null
|
||||
|
||||
var bellController: BellController? = null
|
||||
|
||||
override fun onTextChanged(changedSession: TerminalSession?) {
|
||||
termSessionData?.termView?.onScreenUpdated()
|
||||
}
|
||||
|
||||
override fun onTitleChanged(changedSession: TerminalSession?) {
|
||||
if (changedSession?.title != null) {
|
||||
termSessionData?.termUI?.requireUpdateTitle(changedSession.title)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSessionFinished(finishedSession: TerminalSession?) {
|
||||
termSessionData?.termUI?.requireOnSessionFinished()
|
||||
}
|
||||
|
||||
override fun onClipboardText(session: TerminalSession?, text: String?) {
|
||||
val termView = termSessionData?.termView
|
||||
if (termView != null) {
|
||||
val clipboard = termView.context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard.primaryClip = ClipData.newPlainText("", text)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBell(session: TerminalSession?) {
|
||||
val termView = termSessionData?.termView ?: return
|
||||
val shellSession = session as ShellTermSession
|
||||
|
||||
if (bellController == null) {
|
||||
bellController = BellController()
|
||||
}
|
||||
|
||||
bellController?.bellOrVibrate(termView.context, shellSession)
|
||||
}
|
||||
|
||||
override fun onColorsChanged(session: TerminalSession?) {
|
||||
val termView = termSessionData?.termView
|
||||
if (session != null && termView != null) {
|
||||
termView.onScreenUpdated()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BellController {
|
||||
companion object {
|
||||
private val BELL_DELAY_MS = 100
|
||||
}
|
||||
|
||||
private var bellId: Int = 0
|
||||
private var soundPool: SoundPool? = null
|
||||
private var lastBellTime = 0L
|
||||
|
||||
fun bellOrVibrate(context: Context, session: ShellTermSession) {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (currentTime - lastBellTime < BELL_DELAY_MS) {
|
||||
return
|
||||
}
|
||||
lastBellTime = currentTime
|
||||
|
||||
if (session.shellProfile.enableBell) {
|
||||
if (soundPool == null) {
|
||||
soundPool = SoundPool.Builder().setMaxStreams(1).build()
|
||||
bellId = soundPool!!.load(context, R.raw.bell, 1)
|
||||
}
|
||||
soundPool?.play(bellId, 1f, 1f, 0, 0, 1f)
|
||||
}
|
||||
|
||||
if (session.shellProfile.enableVibrate) {
|
||||
val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
vibrator.vibrate(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TermCompleteListener(var terminalView: TerminalView?) : OnAutoCompleteListener, OnCandidateSelectedListener {
|
||||
private val inputStack = Stack<Char>()
|
||||
private var popupWindow: CandidatePopupWindow? = null
|
||||
private var lastCompletedIndex = 0
|
||||
|
||||
override fun onKeyCode(keyCode: Int, keyMod: Int) {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_DEL -> {
|
||||
popChar()
|
||||
fixLastCompletedIndex()
|
||||
triggerCompletion()
|
||||
}
|
||||
|
||||
KeyEvent.KEYCODE_ENTER -> {
|
||||
clearChars()
|
||||
popupWindow?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fixLastCompletedIndex() {
|
||||
val currentText = getCurrentEditingText()
|
||||
lastCompletedIndex = minOf(lastCompletedIndex, currentText.length - 1)
|
||||
}
|
||||
|
||||
override fun onCompletionRequired(newText: String?) {
|
||||
if (newText == null || newText.isEmpty()) {
|
||||
return
|
||||
}
|
||||
pushString(newText)
|
||||
triggerCompletion()
|
||||
}
|
||||
|
||||
override fun onCleanUp() {
|
||||
popupWindow?.dismiss()
|
||||
popupWindow?.cleanup()
|
||||
popupWindow = null
|
||||
terminalView = null
|
||||
}
|
||||
|
||||
override fun onFinishCompletion(): Boolean {
|
||||
val popWindow = popupWindow ?: return false
|
||||
|
||||
if (popWindow.isShowing()) {
|
||||
popWindow.dismiss()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onCandidateSelected(candidate: CompletionCandidate) {
|
||||
val session = terminalView?.currentSession ?: return
|
||||
val textNeedCompletion = getCurrentEditingText().substring(lastCompletedIndex + 1)
|
||||
val newText = candidate.completeString
|
||||
|
||||
val deleteLength = newText.indexOf(textNeedCompletion) + textNeedCompletion.length
|
||||
if (deleteLength > 0) {
|
||||
for (i in 0 until deleteLength) {
|
||||
session.write("\b")
|
||||
popChar()
|
||||
}
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e(
|
||||
"NeoTerm-AC",
|
||||
"currentEditing: $textNeedCompletion, " +
|
||||
"deleteLength: $deleteLength, completeString: $newText"
|
||||
)
|
||||
}
|
||||
|
||||
pushString(newText)
|
||||
session.write(newText)
|
||||
// Trigger next completion
|
||||
lastCompletedIndex = inputStack.size
|
||||
triggerCompletion()
|
||||
}
|
||||
|
||||
private fun triggerCompletion() {
|
||||
val text = getCurrentEditingText()
|
||||
if (text.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val result = CompletionManager.tryCompleteFor(text)
|
||||
if (!result.hasResult()) {
|
||||
// A provider accepted the task
|
||||
// But no candidates are provided
|
||||
// Give it zero angrily!
|
||||
result.markScore(0)
|
||||
onFinishCompletion()
|
||||
return
|
||||
}
|
||||
showAutoCompleteCandidates(result)
|
||||
}
|
||||
|
||||
private fun showAutoCompleteCandidates(result: CompletionResult) {
|
||||
val termView = terminalView
|
||||
var popWindow = popupWindow
|
||||
|
||||
if (termView == null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (popWindow == null) {
|
||||
popWindow = CandidatePopupWindow(termView.context)
|
||||
popWindow.onCandidateSelectedListener = this
|
||||
this.popupWindow = popWindow
|
||||
}
|
||||
|
||||
popWindow.candidates = result.candidates
|
||||
popWindow.show(termView)
|
||||
}
|
||||
|
||||
private fun getCurrentEditingText(): String {
|
||||
val builder = StringBuilder()
|
||||
val size = inputStack.size
|
||||
var start = inputStack.lastIndexOf(' ')
|
||||
if (start < 0) {
|
||||
// Yes, it is -1, we will do `start + 1` below.
|
||||
start = -1
|
||||
}
|
||||
|
||||
IntRange(start + 1, size - 1)
|
||||
.map { inputStack[it] }
|
||||
.takeWhile { !(it == 0.toChar() || it == ' ') }
|
||||
.forEach { builder.append(it) }
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private fun clearChars() {
|
||||
inputStack.clear()
|
||||
lastCompletedIndex = 0
|
||||
}
|
||||
|
||||
private fun popChar() {
|
||||
if (inputStack.isNotEmpty()) {
|
||||
inputStack.pop()
|
||||
}
|
||||
}
|
||||
|
||||
private fun pushString(string: String) {
|
||||
string.toCharArray().forEach { pushChar(it) }
|
||||
}
|
||||
|
||||
private fun pushChar(char: Char) {
|
||||
inputStack.push(char)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.terminal
|
||||
package io.neoterm.frontend.session.view
|
||||
|
||||
import android.content.Context
|
||||
import android.view.GestureDetector
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.terminal;
|
||||
package io.neoterm.frontend.session.view;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.terminal;
|
||||
package io.neoterm.frontend.session.view;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
@ -23,7 +23,7 @@ import android.view.inputmethod.InputConnection;
|
||||
import android.widget.Scroller;
|
||||
import io.neoterm.R;
|
||||
import io.neoterm.backend.*;
|
||||
import io.neoterm.frontend.completion.listener.OnAutoCompleteListener;
|
||||
import io.neoterm.component.completion.OnAutoCompleteListener;
|
||||
|
||||
/**
|
||||
* View displaying and interacting with a {@link TerminalSession}.
|
||||
@ -1032,10 +1032,8 @@ public final class TerminalView extends View {
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
mActionMode = startActionMode(new ActionMode.Callback2() {
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
@ -1066,11 +1064,6 @@ public final class TerminalView extends View {
|
||||
outRect.set(Math.min(x1, x2), y1, Math.max(x1, x2), y2);
|
||||
}
|
||||
}, ActionMode.TYPE_FLOATING);
|
||||
} else {
|
||||
mActionMode = startActionMode(callback);
|
||||
}
|
||||
|
||||
|
||||
invalidate();
|
||||
} else {
|
||||
mActionMode.finish();
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.terminal;
|
||||
package io.neoterm.frontend.session.view;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
@ -11,7 +11,6 @@ import io.neoterm.backend.TerminalSession;
|
||||
* <p/>
|
||||
*/
|
||||
public interface TerminalViewClient {
|
||||
|
||||
/**
|
||||
* Callback function on scale events according to {@link ScaleGestureDetector#getScaleFactor()}.
|
||||
*/
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.terminal.extrakey.combine
|
||||
package io.neoterm.frontend.session.view.extrakey
|
||||
|
||||
/**
|
||||
* <Ctrl> <Alt> <Delete>
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.frontend.terminal.extrakey
|
||||
package io.neoterm.frontend.session.view.extrakey
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
@ -7,21 +7,15 @@ import android.view.*
|
||||
import android.widget.GridLayout
|
||||
import android.widget.LinearLayout
|
||||
import io.neoterm.R
|
||||
import io.neoterm.component.ComponentManager
|
||||
import io.neoterm.component.config.NeoPreference
|
||||
import io.neoterm.component.config.NeoTermPath
|
||||
import io.neoterm.component.extrakey.ExtraKeyComponent
|
||||
import io.neoterm.frontend.component.ComponentManager
|
||||
import io.neoterm.frontend.config.NeoPreference
|
||||
import io.neoterm.frontend.config.NeoTermPath
|
||||
import io.neoterm.frontend.session.shell.client.event.ToggleImeEvent
|
||||
import io.neoterm.frontend.terminal.extrakey.button.ControlButton
|
||||
import io.neoterm.frontend.terminal.extrakey.button.IExtraButton
|
||||
import io.neoterm.frontend.terminal.extrakey.button.RepeatableButton
|
||||
import io.neoterm.frontend.terminal.extrakey.button.StatedControlButton
|
||||
import io.neoterm.frontend.terminal.extrakey.impl.ArrowButton
|
||||
import io.neoterm.frontend.session.terminal.ToggleImeEvent
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.io.File
|
||||
|
||||
class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
|
||||
|
||||
companion object {
|
||||
private val ESC = ControlButton(IExtraButton.KEY_ESC)
|
||||
private val TAB = ControlButton(IExtraButton.KEY_TAB)
|
||||
@ -68,7 +62,7 @@ class ExtraKeysView(context: Context, attrs: AttributeSet) : LinearLayout(contex
|
||||
init {
|
||||
alpha = DEFAULT_ALPHA
|
||||
gravity = Gravity.TOP
|
||||
orientation = LinearLayout.VERTICAL
|
||||
orientation = VERTICAL
|
||||
typeface = Typeface.createFromAsset(context.assets, "eks_font.ttf")
|
||||
extraKeyComponent = ComponentManager.getComponent<ExtraKeyComponent>()
|
||||
|
@ -0,0 +1,222 @@
|
||||
package io.neoterm.frontend.session.view.extrakey
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.AttributeSet
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.ToggleButton
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import io.neoterm.R
|
||||
import io.neoterm.frontend.session.view.TerminalView
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
open class ControlButton(text: String) : TextButton(text, false)
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
abstract class IExtraButton : View.OnClickListener {
|
||||
|
||||
var buttonKeys: CombinedSequence? = null
|
||||
var displayText: String? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "${this.javaClass.simpleName} { display: $displayText, code: ${buttonKeys?.keys} }"
|
||||
}
|
||||
|
||||
abstract override fun onClick(view: View)
|
||||
|
||||
abstract fun makeButton(context: Context?, attrs: AttributeSet?, defStyleAttr: Int): Button
|
||||
|
||||
companion object {
|
||||
const val KEY_ESC = "Esc"
|
||||
const val KEY_TAB = "Tab"
|
||||
const val KEY_CTRL = "Ctrl"
|
||||
const val KEY_ALT = "Alt"
|
||||
const val KEY_PAGE_UP = "PgUp"
|
||||
const val KEY_PAGE_DOWN = "PgDn"
|
||||
const val KEY_HOME = "Home"
|
||||
const val KEY_END = "End"
|
||||
const val KEY_ARROW_UP_TEXT = "Up"
|
||||
const val KEY_ARROW_DOWN_TEXT = "Down"
|
||||
const val KEY_ARROW_LEFT_TEXT = "Left"
|
||||
const val KEY_ARROW_RIGHT_TEXT = "Right"
|
||||
const val KEY_SHOW_ALL_BUTTONS = "···"
|
||||
const val KEY_TOGGLE_IME = "Im"
|
||||
|
||||
const val KEY_ARROW_UP = "▲"
|
||||
const val KEY_ARROW_DOWN = "▼"
|
||||
const val KEY_ARROW_LEFT = "◀"
|
||||
const val KEY_ARROW_RIGHT = "▶"
|
||||
|
||||
var NORMAL_TEXT_COLOR = 0xFFFFFFFF.toInt()
|
||||
var SELECTED_TEXT_COLOR = 0xFF80DEEA.toInt()
|
||||
|
||||
fun sendKey(view: View, keyName: String) {
|
||||
var keyCode = 0
|
||||
var chars = ""
|
||||
when (keyName) {
|
||||
KEY_ESC -> keyCode = KeyEvent.KEYCODE_ESCAPE
|
||||
KEY_TAB -> keyCode = KeyEvent.KEYCODE_TAB
|
||||
KEY_ARROW_UP -> keyCode = KeyEvent.KEYCODE_DPAD_UP
|
||||
KEY_ARROW_LEFT -> keyCode = KeyEvent.KEYCODE_DPAD_LEFT
|
||||
KEY_ARROW_RIGHT -> keyCode = KeyEvent.KEYCODE_DPAD_RIGHT
|
||||
KEY_ARROW_DOWN -> keyCode = KeyEvent.KEYCODE_DPAD_DOWN
|
||||
KEY_ARROW_UP_TEXT -> keyCode = KeyEvent.KEYCODE_DPAD_UP
|
||||
KEY_ARROW_LEFT_TEXT -> keyCode = KeyEvent.KEYCODE_DPAD_LEFT
|
||||
KEY_ARROW_RIGHT_TEXT -> keyCode = KeyEvent.KEYCODE_DPAD_RIGHT
|
||||
KEY_ARROW_DOWN_TEXT -> keyCode = KeyEvent.KEYCODE_DPAD_DOWN
|
||||
KEY_PAGE_UP -> keyCode = KeyEvent.KEYCODE_PAGE_UP
|
||||
KEY_PAGE_DOWN -> keyCode = KeyEvent.KEYCODE_PAGE_DOWN
|
||||
KEY_HOME -> keyCode = KeyEvent.KEYCODE_MOVE_HOME
|
||||
KEY_END -> keyCode = KeyEvent.KEYCODE_MOVE_END
|
||||
"―" -> chars = "-"
|
||||
else -> chars = keyName
|
||||
}
|
||||
|
||||
if (keyCode > 0) {
|
||||
view.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, keyCode))
|
||||
view.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, keyCode))
|
||||
} else if (chars.isNotEmpty()) {
|
||||
val terminalView = view.findViewById<TerminalView>(R.id.terminal_view)
|
||||
val session = terminalView.currentSession
|
||||
session?.write(chars)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class RepeatableButton(buttonText: String) : ControlButton(buttonText) {
|
||||
|
||||
override fun makeButton(context: Context?, attrs: AttributeSet?, defStyleAttr: Int): Button {
|
||||
return RepeatableButtonWidget(context, attrs, defStyleAttr)
|
||||
}
|
||||
|
||||
private class RepeatableButtonWidget(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) :
|
||||
AppCompatButton(context!!, attrs, defStyleAttr) {
|
||||
|
||||
/**
|
||||
* Milliseconds how long we trigger an action
|
||||
* when long pressing
|
||||
*/
|
||||
private val LONG_CLICK_ACTION_INTERVAL = 100L
|
||||
|
||||
private var isMotionEventUp = true
|
||||
|
||||
var mHandler: Handler = object : Handler(Looper.getMainLooper()) {
|
||||
override fun handleMessage(msg: android.os.Message) {
|
||||
if (!isMotionEventUp && isEnabled) {
|
||||
performClick()
|
||||
this.sendEmptyMessageDelayed(0, LONG_CLICK_ACTION_INTERVAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
this.setOnLongClickListener {
|
||||
isMotionEventUp = false
|
||||
mHandler.sendEmptyMessage(0)
|
||||
false
|
||||
}
|
||||
this.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_UP) {
|
||||
isMotionEventUp = true
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun performClick(): Boolean {
|
||||
return super.performClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
open class StatedControlButton @JvmOverloads constructor(text: String, var initState: Boolean = false) :
|
||||
ControlButton(text) {
|
||||
var toggleButton: ToggleButton? = null
|
||||
|
||||
override fun onClick(view: View) {
|
||||
setStatus(toggleButton?.isChecked)
|
||||
}
|
||||
|
||||
override fun makeButton(context: Context?, attrs: AttributeSet?, defStyleAttr: Int): Button {
|
||||
val outerButton = ToggleButton(context, null, android.R.attr.buttonBarButtonStyle)
|
||||
|
||||
outerButton.isClickable = true
|
||||
if (initState) {
|
||||
outerButton.isChecked = true
|
||||
outerButton.setTextColor(SELECTED_TEXT_COLOR)
|
||||
}
|
||||
|
||||
this.toggleButton = outerButton
|
||||
return outerButton
|
||||
}
|
||||
|
||||
private fun setStatus(status: Boolean?) {
|
||||
val button = toggleButton
|
||||
if (button != null && status != null) {
|
||||
button.isChecked = status
|
||||
button.setTextColor(
|
||||
if (status) SELECTED_TEXT_COLOR
|
||||
else NORMAL_TEXT_COLOR
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun readState(): Boolean {
|
||||
val button = toggleButton ?: return false
|
||||
|
||||
if (button.isPressed) return true
|
||||
val result = button.isChecked
|
||||
if (result) {
|
||||
button.isChecked = false
|
||||
button.setTextColor(NORMAL_TEXT_COLOR)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
open class TextButton constructor(text: String, val withEnter: Boolean = false) : IExtraButton() {
|
||||
init {
|
||||
this.buttonKeys = CombinedSequence.solveString(text)
|
||||
this.displayText = text
|
||||
}
|
||||
|
||||
override fun onClick(view: View) {
|
||||
buttonKeys!!.keys.forEach {
|
||||
sendKey(view, it)
|
||||
}
|
||||
if (withEnter) {
|
||||
sendKey(view, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
override fun makeButton(context: Context?, attrs: AttributeSet?, defStyleAttr: Int): Button {
|
||||
return Button(context, attrs, defStyleAttr)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ArrowButton(arrowText: String) : RepeatableButton(arrowText)
|
@ -1,8 +0,0 @@
|
||||
package io.neoterm.frontend.session.xorg;
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
public class XParameter {
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package io.neoterm.frontend.session.xorg.client
|
||||
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import io.neoterm.NeoAudioThread
|
||||
import io.neoterm.NeoGLView
|
||||
import io.neoterm.xorg.NeoXorgViewClient
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class XSessionData {
|
||||
var videoLayout: FrameLayout? = null
|
||||
var audioThread: NeoAudioThread? = null
|
||||
var screenKeyboard: View? = null
|
||||
var glView: NeoGLView? = null
|
||||
|
||||
var isPaused = false
|
||||
var client: NeoXorgViewClient? = null
|
||||
|
||||
var keyboardWithoutTextInputShown = false
|
||||
var screenKeyboardHintMessage: String? = null
|
||||
var textInput = LinkedList<Int>()
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package io.neoterm.frontend.terminal.extrakey.button
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
open class ControlButton(text: String) : TextButton(text, false)
|
@ -1,85 +0,0 @@
|
||||
package io.neoterm.frontend.terminal.extrakey.button
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import io.neoterm.R
|
||||
import io.neoterm.frontend.terminal.TerminalView
|
||||
import io.neoterm.frontend.terminal.extrakey.combine.CombinedSequence
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
abstract class IExtraButton : View.OnClickListener {
|
||||
|
||||
var buttonKeys: CombinedSequence? = null
|
||||
var displayText: String? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "${this.javaClass.simpleName} { display: $displayText, code: ${buttonKeys?.keys} }"
|
||||
}
|
||||
|
||||
abstract override fun onClick(view: View)
|
||||
|
||||
abstract fun makeButton(context: Context?, attrs: AttributeSet?, defStyleAttr: Int): Button
|
||||
|
||||
companion object {
|
||||
val KEY_ESC = "Esc"
|
||||
val KEY_TAB = "Tab"
|
||||
val KEY_CTRL = "Ctrl"
|
||||
val KEY_ALT = "Alt"
|
||||
val KEY_PAGE_UP = "PgUp"
|
||||
val KEY_PAGE_DOWN = "PgDn"
|
||||
val KEY_HOME = "Home"
|
||||
val KEY_END = "End"
|
||||
val KEY_ARROW_UP_TEXT = "Up"
|
||||
val KEY_ARROW_DOWN_TEXT = "Down"
|
||||
val KEY_ARROW_LEFT_TEXT = "Left"
|
||||
val KEY_ARROW_RIGHT_TEXT = "Right"
|
||||
val KEY_SHOW_ALL_BUTTONS = "···"
|
||||
val KEY_TOGGLE_IME = "Im"
|
||||
|
||||
val KEY_ARROW_UP = "▲"
|
||||
val KEY_ARROW_DOWN = "▼"
|
||||
val KEY_ARROW_LEFT = "◀"
|
||||
val KEY_ARROW_RIGHT = "▶"
|
||||
|
||||
var NORMAL_TEXT_COLOR = 0xFFFFFFFF.toInt()
|
||||
var SELECTED_TEXT_COLOR = 0xFF80DEEA.toInt()
|
||||
|
||||
fun sendKey(view: View, keyName: String) {
|
||||
var keyCode = 0
|
||||
var chars = ""
|
||||
when (keyName) {
|
||||
KEY_ESC -> keyCode = KeyEvent.KEYCODE_ESCAPE
|
||||
KEY_TAB -> keyCode = KeyEvent.KEYCODE_TAB
|
||||
KEY_ARROW_UP -> keyCode = KeyEvent.KEYCODE_DPAD_UP
|
||||
KEY_ARROW_LEFT -> keyCode = KeyEvent.KEYCODE_DPAD_LEFT
|
||||
KEY_ARROW_RIGHT -> keyCode = KeyEvent.KEYCODE_DPAD_RIGHT
|
||||
KEY_ARROW_DOWN -> keyCode = KeyEvent.KEYCODE_DPAD_DOWN
|
||||
KEY_ARROW_UP_TEXT -> keyCode = KeyEvent.KEYCODE_DPAD_UP
|
||||
KEY_ARROW_LEFT_TEXT -> keyCode = KeyEvent.KEYCODE_DPAD_LEFT
|
||||
KEY_ARROW_RIGHT_TEXT -> keyCode = KeyEvent.KEYCODE_DPAD_RIGHT
|
||||
KEY_ARROW_DOWN_TEXT -> keyCode = KeyEvent.KEYCODE_DPAD_DOWN
|
||||
KEY_PAGE_UP -> keyCode = KeyEvent.KEYCODE_PAGE_UP
|
||||
KEY_PAGE_DOWN -> keyCode = KeyEvent.KEYCODE_PAGE_DOWN
|
||||
KEY_HOME -> keyCode = KeyEvent.KEYCODE_MOVE_HOME
|
||||
KEY_END -> keyCode = KeyEvent.KEYCODE_MOVE_END
|
||||
"―" -> chars = "-"
|
||||
else -> chars = keyName
|
||||
}
|
||||
|
||||
if (keyCode > 0) {
|
||||
view.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, keyCode))
|
||||
view.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, keyCode))
|
||||
} else if (chars.isNotEmpty()) {
|
||||
val terminalView = view.findViewById<TerminalView>(R.id.terminal_view)
|
||||
val session = terminalView.currentSession
|
||||
session?.write(chars)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package io.neoterm.frontend.terminal.extrakey.button
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.widget.Button
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class RepeatableButton(buttonText: String) : ControlButton(buttonText) {
|
||||
|
||||
override fun makeButton(context: Context?, attrs: AttributeSet?, defStyleAttr: Int): Button {
|
||||
return RepeatableButtonWidget(context, attrs, defStyleAttr)
|
||||
}
|
||||
|
||||
private class RepeatableButtonWidget(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) :
|
||||
AppCompatButton(context!!, attrs, defStyleAttr) {
|
||||
|
||||
/**
|
||||
* Milliseconds how long we trigger an action
|
||||
* when long pressing
|
||||
*/
|
||||
private val LONG_CLICK_ACTION_INTERVAL = 100L
|
||||
|
||||
private var isMotionEventUp = true
|
||||
|
||||
var mHandler: Handler = object : Handler(Looper.getMainLooper()) {
|
||||
override fun handleMessage(msg: android.os.Message) {
|
||||
if (!isMotionEventUp && isEnabled) {
|
||||
performClick()
|
||||
this.sendEmptyMessageDelayed(0, LONG_CLICK_ACTION_INTERVAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
this.setOnLongClickListener {
|
||||
isMotionEventUp = false
|
||||
mHandler.sendEmptyMessage(0)
|
||||
false
|
||||
}
|
||||
this.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_UP) {
|
||||
isMotionEventUp = true
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun performClick(): Boolean {
|
||||
return super.performClick()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package io.neoterm.frontend.terminal.extrakey.button
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.ToggleButton
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
open class StatedControlButton @JvmOverloads constructor(text: String, var initState: Boolean = false) :
|
||||
ControlButton(text) {
|
||||
var toggleButton: ToggleButton? = null
|
||||
|
||||
override fun onClick(view: View) {
|
||||
setStatus(toggleButton?.isChecked)
|
||||
}
|
||||
|
||||
override fun makeButton(context: Context?, attrs: AttributeSet?, defStyleAttr: Int): Button {
|
||||
val outerButton = ToggleButton(context, null, android.R.attr.buttonBarButtonStyle)
|
||||
|
||||
outerButton.isClickable = true
|
||||
if (initState) {
|
||||
outerButton.isChecked = true
|
||||
outerButton.setTextColor(IExtraButton.SELECTED_TEXT_COLOR)
|
||||
}
|
||||
|
||||
this.toggleButton = outerButton
|
||||
return outerButton
|
||||
}
|
||||
|
||||
private fun setStatus(status: Boolean?) {
|
||||
val button = toggleButton
|
||||
if (button != null && status != null) {
|
||||
button.isChecked = status
|
||||
button.setTextColor(
|
||||
if (status) SELECTED_TEXT_COLOR
|
||||
else NORMAL_TEXT_COLOR
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun readState(): Boolean {
|
||||
val button = toggleButton ?: return false
|
||||
|
||||
if (button.isPressed) return true
|
||||
val result = button.isChecked
|
||||
if (result) {
|
||||
button.isChecked = false
|
||||
button.setTextColor(NORMAL_TEXT_COLOR)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package io.neoterm.frontend.terminal.extrakey.button
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import io.neoterm.frontend.terminal.extrakey.combine.CombinedSequence
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
open class TextButton constructor(text: String, val withEnter: Boolean = false) : IExtraButton() {
|
||||
init {
|
||||
this.buttonKeys = CombinedSequence.solveString(text)
|
||||
this.displayText = text
|
||||
}
|
||||
|
||||
override fun onClick(view: View) {
|
||||
buttonKeys!!.keys.forEach {
|
||||
sendKey(view, it)
|
||||
}
|
||||
if (withEnter) {
|
||||
sendKey(view, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
override fun makeButton(context: Context?, attrs: AttributeSet?, defStyleAttr: Int): Button {
|
||||
return Button(context, attrs, defStyleAttr)
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package io.neoterm.frontend.terminal.extrakey.impl
|
||||
|
||||
import io.neoterm.frontend.terminal.extrakey.button.RepeatableButton
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class ArrowButton(arrowText: String) : RepeatableButton(arrowText)
|
@ -14,11 +14,11 @@ import androidx.core.app.NotificationCompat
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.EmulatorDebug
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.frontend.logging.NLog
|
||||
import io.neoterm.frontend.session.shell.ShellParameter
|
||||
import io.neoterm.frontend.session.xorg.XParameter
|
||||
import io.neoterm.frontend.session.xorg.XSession
|
||||
import io.neoterm.component.session.ShellParameter
|
||||
import io.neoterm.component.session.XParameter
|
||||
import io.neoterm.component.session.XSession
|
||||
import io.neoterm.ui.term.NeoTermActivity
|
||||
import io.neoterm.utils.NLog
|
||||
import io.neoterm.utils.Terminals
|
||||
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
package io.neoterm.setup
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface ResultListener {
|
||||
fun onResult(error: Exception?)
|
||||
}
|
@ -5,8 +5,8 @@ import android.system.Os;
|
||||
import android.util.Pair;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import io.neoterm.backend.EmulatorDebug;
|
||||
import io.neoterm.frontend.config.NeoTermPath;
|
||||
import io.neoterm.frontend.logging.NLog;
|
||||
import io.neoterm.component.config.NeoTermPath;
|
||||
import io.neoterm.utils.NLog;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
|
@ -8,8 +8,6 @@ import java.io.InputStream;
|
||||
*/
|
||||
public interface SourceConnection {
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
||||
int getSize();
|
||||
|
||||
void close();
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user