├── .editorconfig ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Cargo.toml ├── LICENSE ├── Makefile.toml ├── NOTICE ├── README.md ├── README.tpl ├── cliff.toml ├── clippy.toml ├── dist-workspace.toml ├── examples ├── Cargo.kdl ├── ci.kdl ├── custom-errors.rs ├── insert-node.rs ├── kdl-schema.kdl ├── nuget.kdl ├── website.kdl ├── zellij-unquoted-bindings.kdl └── zellij.kdl ├── src ├── document.rs ├── entry.rs ├── error.rs ├── fmt.rs ├── identifier.rs ├── lib.rs ├── node.rs ├── nom_compat.rs ├── query.rs ├── query_parser.rs ├── v1_parser.rs ├── v2_parser.rs └── value.rs ├── tests ├── README.md ├── compliance.rs ├── disabled_tests │ ├── query_api.rs │ ├── query_matchers.rs │ ├── query_ops.rs │ └── query_syntax.rs ├── formatting.rs └── test_cases │ ├── expected_kdl │ ├── all_escapes.kdl │ ├── all_node_fields.kdl │ ├── arg_and_prop_same_name.kdl │ ├── arg_bare.kdl │ ├── arg_false_type.kdl │ ├── arg_float_type.kdl │ ├── arg_hex_type.kdl │ ├── arg_null_type.kdl │ ├── arg_raw_string_type.kdl │ ├── arg_string_type.kdl │ ├── arg_true_type.kdl │ ├── arg_type.kdl │ ├── arg_zero_type.kdl │ ├── asterisk_in_block_comment.kdl │ ├── bare_emoji.kdl │ ├── bare_ident_dot.kdl │ ├── bare_ident_sign.kdl │ ├── bare_ident_sign_dot.kdl │ ├── binary.kdl │ ├── binary_trailing_underscore.kdl │ ├── binary_underscore.kdl │ ├── blank_arg_type.kdl │ ├── blank_node_type.kdl │ ├── blank_prop_type.kdl │ ├── block_comment.kdl │ ├── block_comment_after_node.kdl │ ├── block_comment_before_node.kdl │ ├── block_comment_before_node_no_space.kdl │ ├── block_comment_newline.kdl │ ├── bom_initial.kdl │ ├── boolean_arg.kdl │ ├── boolean_prop.kdl │ ├── chevrons_in_bare_id.kdl │ ├── comma_in_bare_id.kdl │ ├── comment_after_arg_type.kdl │ ├── comment_after_node_type.kdl │ ├── comment_after_prop_type.kdl │ ├── comment_and_newline.kdl │ ├── comment_in_arg_type.kdl │ ├── comment_in_node_type.kdl │ ├── comment_in_prop_type.kdl │ ├── commented_arg.kdl │ ├── commented_child.kdl │ ├── commented_line.kdl │ ├── commented_node.kdl │ ├── commented_prop.kdl │ ├── crlf_between_nodes.kdl │ ├── dash_dash.kdl │ ├── emoji.kdl │ ├── empty.kdl │ ├── empty_child.kdl │ ├── empty_child_different_lines.kdl │ ├── empty_child_same_line.kdl │ ├── empty_child_whitespace.kdl │ ├── empty_line_comment.kdl │ ├── empty_quoted_node_id.kdl │ ├── empty_quoted_prop_key.kdl │ ├── empty_string_arg.kdl │ ├── eof_after_escape.kdl │ ├── esc_multiple_newlines.kdl │ ├── esc_newline_in_string.kdl │ ├── esc_unicode_in_string.kdl │ ├── escaped_whitespace.kdl │ ├── escline.kdl │ ├── escline_after_semicolon.kdl │ ├── escline_alone.kdl │ ├── escline_empty_line.kdl │ ├── escline_end_of_node.kdl │ ├── escline_in_child_block.kdl │ ├── escline_line_comment.kdl │ ├── escline_node.kdl │ ├── escline_node_type.kdl │ ├── escline_slashdash.kdl │ ├── false_prefix_in_bare_id.kdl │ ├── false_prefix_in_prop_key.kdl │ ├── floating_point_keywords.kdl │ ├── hex_int.kdl │ ├── hex_int_underscores.kdl │ ├── hex_leading_zero.kdl │ ├── initial_slashdash.kdl │ ├── int_multiple_underscore.kdl │ ├── just_block_comment.kdl │ ├── just_child.kdl │ ├── just_newline.kdl │ ├── just_node_id.kdl │ ├── just_space.kdl │ ├── leading_newline.kdl │ ├── leading_zero_binary.kdl │ ├── leading_zero_int.kdl │ ├── leading_zero_oct.kdl │ ├── multiline_comment.kdl │ ├── multiline_nodes.kdl │ ├── multiline_raw_string.kdl │ ├── multiline_raw_string_containing_quotes.kdl │ ├── multiline_raw_string_indented.kdl │ ├── multiline_string.kdl │ ├── multiline_string_containing_quotes.kdl │ ├── multiline_string_double_backslash.kdl │ ├── multiline_string_escape_delimiter.kdl │ ├── multiline_string_escape_in_closing_line.kdl │ ├── multiline_string_escape_in_closing_line_shallow.kdl │ ├── multiline_string_escape_newline_at_end.kdl │ ├── multiline_string_indented.kdl │ ├── multiline_string_whitespace_only.kdl │ ├── negative_exponent.kdl │ ├── negative_float.kdl │ ├── negative_int.kdl │ ├── nested_block_comment.kdl │ ├── nested_children.kdl │ ├── nested_comments.kdl │ ├── nested_multiline_block_comment.kdl │ ├── newline_between_nodes.kdl │ ├── newlines_in_block_comment.kdl │ ├── no_decimal_exponent.kdl │ ├── node_false.kdl │ ├── node_true.kdl │ ├── node_type.kdl │ ├── null_arg.kdl │ ├── null_prefix_in_bare_id.kdl │ ├── null_prefix_in_prop_key.kdl │ ├── null_prop.kdl │ ├── numeric_arg.kdl │ ├── numeric_prop.kdl │ ├── octal.kdl │ ├── only_cr.kdl │ ├── only_line_comment.kdl │ ├── only_line_comment_crlf.kdl │ ├── only_line_comment_newline.kdl │ ├── optional_child_semicolon.kdl │ ├── parse_all_arg_types.kdl │ ├── positive_exponent.kdl │ ├── positive_int.kdl │ ├── preserve_duplicate_nodes.kdl │ ├── preserve_node_order.kdl │ ├── prop_false_type.kdl │ ├── prop_float_type.kdl │ ├── prop_hex_type.kdl │ ├── prop_identifier_type.kdl │ ├── prop_null_type.kdl │ ├── prop_raw_string_type.kdl │ ├── prop_string_type.kdl │ ├── prop_true_type.kdl │ ├── prop_type.kdl │ ├── prop_zero_type.kdl │ ├── question_mark_before_number.kdl │ ├── quoted_arg_type.kdl │ ├── quoted_node_name.kdl │ ├── quoted_node_type.kdl │ ├── quoted_numeric.kdl │ ├── quoted_prop_name.kdl │ ├── quoted_prop_type.kdl │ ├── r_node.kdl │ ├── raw_arg_type.kdl │ ├── raw_node_name.kdl │ ├── raw_node_type.kdl │ ├── raw_prop_type.kdl │ ├── raw_string_arg.kdl │ ├── raw_string_backslash.kdl │ ├── raw_string_hash_no_esc.kdl │ ├── raw_string_just_backslash.kdl │ ├── raw_string_multiple_hash.kdl │ ├── raw_string_newline.kdl │ ├── raw_string_prop.kdl │ ├── raw_string_quote.kdl │ ├── repeated_arg.kdl │ ├── repeated_prop.kdl │ ├── same_name_nodes.kdl │ ├── sci_notation_large.kdl │ ├── sci_notation_small.kdl │ ├── semicolon_after_child.kdl │ ├── semicolon_in_child.kdl │ ├── semicolon_separated.kdl │ ├── semicolon_separated_nodes.kdl │ ├── semicolon_terminated.kdl │ ├── single_arg.kdl │ ├── single_prop.kdl │ ├── slashdash_arg_after_newline_esc.kdl │ ├── slashdash_arg_before_newline_esc.kdl │ ├── slashdash_child.kdl │ ├── slashdash_empty_child.kdl │ ├── slashdash_escline_before_arg_type.kdl │ ├── slashdash_escline_before_children.kdl │ ├── slashdash_escline_before_node.kdl │ ├── slashdash_false_node.kdl │ ├── slashdash_full_node.kdl │ ├── slashdash_in_slashdash.kdl │ ├── slashdash_multi_line_comment_entry.kdl │ ├── slashdash_multi_line_comment_inline.kdl │ ├── slashdash_multiple_child_blocks.kdl │ ├── slashdash_negative_number.kdl │ ├── slashdash_newline_before_children.kdl │ ├── slashdash_newline_before_entry.kdl │ ├── slashdash_newline_before_node.kdl │ ├── slashdash_node_in_child.kdl │ ├── slashdash_node_with_child.kdl │ ├── slashdash_only_node.kdl │ ├── slashdash_only_node_with_space.kdl │ ├── slashdash_prop.kdl │ ├── slashdash_raw_prop_key.kdl │ ├── slashdash_repeated_prop.kdl │ ├── slashdash_single_line_comment_entry.kdl │ ├── slashdash_single_line_comment_node.kdl │ ├── space_after_arg_type.kdl │ ├── space_after_node_type.kdl │ ├── space_after_prop_type.kdl │ ├── space_around_prop_marker.kdl │ ├── space_in_arg_type.kdl │ ├── space_in_node_type.kdl │ ├── space_in_prop_type.kdl │ ├── string_arg.kdl │ ├── string_escaped_literal_whitespace.kdl │ ├── string_prop.kdl │ ├── tab_space.kdl │ ├── trailing_crlf.kdl │ ├── trailing_underscore_hex.kdl │ ├── trailing_underscore_octal.kdl │ ├── true_prefix_in_bare_id.kdl │ ├── true_prefix_in_prop_key.kdl │ ├── two_nodes.kdl │ ├── underscore_before_number.kdl │ ├── underscore_in_exponent.kdl │ ├── underscore_in_float.kdl │ ├── underscore_in_fraction.kdl │ ├── underscore_in_int.kdl │ ├── underscore_in_octal.kdl │ ├── unicode_silly.kdl │ ├── unusual_bare_id_chars_in_quoted_id.kdl │ ├── unusual_chars_in_bare_id.kdl │ ├── vertical_tab_whitespace.kdl │ ├── zero_float.kdl │ └── zero_int.kdl │ └── input │ ├── all_escapes.kdl │ ├── all_node_fields.kdl │ ├── arg_and_prop_same_name.kdl │ ├── arg_bare.kdl │ ├── arg_false_type.kdl │ ├── arg_float_type.kdl │ ├── arg_hex_type.kdl │ ├── arg_null_type.kdl │ ├── arg_raw_string_type.kdl │ ├── arg_string_type.kdl │ ├── arg_true_type.kdl │ ├── arg_type.kdl │ ├── arg_zero_type.kdl │ ├── asterisk_in_block_comment.kdl │ ├── bare_emoji.kdl │ ├── bare_ident_dot.kdl │ ├── bare_ident_numeric_dot_fail.kdl │ ├── bare_ident_numeric_fail.kdl │ ├── bare_ident_numeric_sign_fail.kdl │ ├── bare_ident_sign.kdl │ ├── bare_ident_sign_dot.kdl │ ├── binary.kdl │ ├── binary_trailing_underscore.kdl │ ├── binary_underscore.kdl │ ├── blank_arg_type.kdl │ ├── blank_node_type.kdl │ ├── blank_prop_type.kdl │ ├── block_comment.kdl │ ├── block_comment_after_node.kdl │ ├── block_comment_before_node.kdl │ ├── block_comment_before_node_no_space.kdl │ ├── block_comment_newline.kdl │ ├── bom_initial.kdl │ ├── bom_later_fail.kdl │ ├── boolean_arg.kdl │ ├── boolean_prop.kdl │ ├── brackets_in_bare_id_fail.kdl │ ├── chevrons_in_bare_id.kdl │ ├── comma_in_bare_id.kdl │ ├── comment_after_arg_type.kdl │ ├── comment_after_node_type.kdl │ ├── comment_after_prop_type.kdl │ ├── comment_and_newline.kdl │ ├── comment_in_arg_type.kdl │ ├── comment_in_node_type.kdl │ ├── comment_in_prop_type.kdl │ ├── commented_arg.kdl │ ├── commented_child.kdl │ ├── commented_line.kdl │ ├── commented_node.kdl │ ├── commented_prop.kdl │ ├── crlf_between_nodes.kdl │ ├── dash_dash.kdl │ ├── dot_but_no_fraction_before_exponent_fail.kdl │ ├── dot_but_no_fraction_fail.kdl │ ├── dot_in_exponent_fail.kdl │ ├── dot_zero_fail.kdl │ ├── emoji.kdl │ ├── empty.kdl │ ├── empty_arg_type_fail.kdl │ ├── empty_child.kdl │ ├── empty_child_different_lines.kdl │ ├── empty_child_same_line.kdl │ ├── empty_child_whitespace.kdl │ ├── empty_line_comment.kdl │ ├── empty_node_type_fail.kdl │ ├── empty_prop_type_fail.kdl │ ├── empty_quoted_node_id.kdl │ ├── empty_quoted_prop_key.kdl │ ├── empty_string_arg.kdl │ ├── eof_after_escape.kdl │ ├── err_backslash_in_bare_id_fail.kdl │ ├── esc_multiple_newlines.kdl │ ├── esc_newline_in_string.kdl │ ├── esc_unicode_in_string.kdl │ ├── escaped_whitespace.kdl │ ├── escline.kdl │ ├── escline_after_semicolon.kdl │ ├── escline_alone.kdl │ ├── escline_empty_line.kdl │ ├── escline_end_of_node.kdl │ ├── escline_in_child_block.kdl │ ├── escline_line_comment.kdl │ ├── escline_node.kdl │ ├── escline_node_type.kdl │ ├── escline_slashdash.kdl │ ├── false_prefix_in_bare_id.kdl │ ├── false_prefix_in_prop_key.kdl │ ├── false_prop_key_fail.kdl │ ├── floating_point_keyword_identifier_strings_fail.kdl │ ├── floating_point_keywords.kdl │ ├── hash_in_id_fail.kdl │ ├── hex.kdl │ ├── hex_int.kdl │ ├── hex_int_underscores.kdl │ ├── hex_leading_zero.kdl │ ├── illegal_char_in_binary_fail.kdl │ ├── illegal_char_in_hex_fail.kdl │ ├── illegal_char_in_octal_fail.kdl │ ├── initial_slashdash.kdl │ ├── int_multiple_underscore.kdl │ ├── just_block_comment.kdl │ ├── just_child.kdl │ ├── just_newline.kdl │ ├── just_node_id.kdl │ ├── just_space.kdl │ ├── just_space_in_arg_type_fail.kdl │ ├── just_space_in_node_type_fail.kdl │ ├── just_space_in_prop_type_fail.kdl │ ├── just_type_no_arg_fail.kdl │ ├── just_type_no_node_id_fail.kdl │ ├── just_type_no_prop_fail.kdl │ ├── leading_newline.kdl │ ├── leading_zero_binary.kdl │ ├── leading_zero_int.kdl │ ├── leading_zero_oct.kdl │ ├── legacy_raw_string_fail.kdl │ ├── legacy_raw_string_hash_fail.kdl │ ├── multiline_comment.kdl │ ├── multiline_nodes.kdl │ ├── multiline_raw_string.kdl │ ├── multiline_raw_string_containing_quotes.kdl │ ├── multiline_raw_string_indented.kdl │ ├── multiline_raw_string_non_matching_prefix_character_error_fail.kdl │ ├── multiline_raw_string_non_matching_prefix_count_error_fail.kdl │ ├── multiline_raw_string_single_line_err_fail.kdl │ ├── multiline_raw_string_single_quote_err_fail.kdl │ ├── multiline_string.kdl │ ├── multiline_string_containing_quotes.kdl │ ├── multiline_string_double_backslash.kdl │ ├── multiline_string_escape_delimiter.kdl │ ├── multiline_string_escape_in_closing_line.kdl │ ├── multiline_string_escape_in_closing_line_shallow.kdl │ ├── multiline_string_escape_newline_at_end.kdl │ ├── multiline_string_escape_newline_at_end_fail.kdl │ ├── multiline_string_final_whitespace_escape_fail.kdl │ ├── multiline_string_indented.kdl │ ├── multiline_string_non_literal_prefix_fail.kdl │ ├── multiline_string_non_matching_prefix_character_error_fail.kdl │ ├── multiline_string_non_matching_prefix_count_error_fail.kdl │ ├── multiline_string_single_line_err_fail.kdl │ ├── multiline_string_single_quote_err_fail.kdl │ ├── multiline_string_whitespace_only.kdl │ ├── multiple_dots_in_float_before_exponent_fail.kdl │ ├── multiple_dots_in_float_fail.kdl │ ├── multiple_es_in_float_fail.kdl │ ├── multiple_x_in_hex_fail.kdl │ ├── negative_exponent.kdl │ ├── negative_float.kdl │ ├── negative_int.kdl │ ├── nested_block_comment.kdl │ ├── nested_children.kdl │ ├── nested_comments.kdl │ ├── nested_multiline_block_comment.kdl │ ├── newline_between_nodes.kdl │ ├── newlines_in_block_comment.kdl │ ├── no_decimal_exponent.kdl │ ├── no_digits_in_hex_fail.kdl │ ├── no_integer_digit_fail.kdl │ ├── no_solidus_escape_fail.kdl │ ├── node_false.kdl │ ├── node_true.kdl │ ├── node_type.kdl │ ├── null_arg.kdl │ ├── null_prefix_in_bare_id.kdl │ ├── null_prefix_in_prop_key.kdl │ ├── null_prop.kdl │ ├── null_prop_key_fail.kdl │ ├── numeric_arg.kdl │ ├── numeric_prop.kdl │ ├── octal.kdl │ ├── only_cr.kdl │ ├── only_line_comment.kdl │ ├── only_line_comment_crlf.kdl │ ├── only_line_comment_newline.kdl │ ├── optional_child_semicolon.kdl │ ├── parens_in_bare_id_fail.kdl │ ├── parse_all_arg_types.kdl │ ├── positive_exponent.kdl │ ├── positive_int.kdl │ ├── preserve_duplicate_nodes.kdl │ ├── preserve_node_order.kdl │ ├── prop_false_type.kdl │ ├── prop_float_type.kdl │ ├── prop_hex_type.kdl │ ├── prop_identifier_type.kdl │ ├── prop_null_type.kdl │ ├── prop_raw_string_type.kdl │ ├── prop_string_type.kdl │ ├── prop_true_type.kdl │ ├── prop_type.kdl │ ├── prop_zero_type.kdl │ ├── question_mark_before_number.kdl │ ├── quote_in_bare_id_fail.kdl │ ├── quoted_arg_type.kdl │ ├── quoted_node_name.kdl │ ├── quoted_node_type.kdl │ ├── quoted_numeric.kdl │ ├── quoted_prop_name.kdl │ ├── quoted_prop_type.kdl │ ├── r_node.kdl │ ├── raw_arg_type.kdl │ ├── raw_node_name.kdl │ ├── raw_node_type.kdl │ ├── raw_prop_type.kdl │ ├── raw_string_arg.kdl │ ├── raw_string_backslash.kdl │ ├── raw_string_hash_no_esc.kdl │ ├── raw_string_just_backslash.kdl │ ├── raw_string_just_quote_fail.kdl │ ├── raw_string_multiple_hash.kdl │ ├── raw_string_newline.kdl │ ├── raw_string_prop.kdl │ ├── raw_string_quote.kdl │ ├── repeated_arg.kdl │ ├── repeated_prop.kdl │ ├── same_name_nodes.kdl │ ├── sci_notation_large.kdl │ ├── sci_notation_small.kdl │ ├── semicolon_after_child.kdl │ ├── semicolon_in_child.kdl │ ├── semicolon_separated.kdl │ ├── semicolon_separated_nodes.kdl │ ├── semicolon_terminated.kdl │ ├── single_arg.kdl │ ├── single_prop.kdl │ ├── slash_in_bare_id_fail.kdl │ ├── slashdash_after_arg_type_fail.kdl │ ├── slashdash_after_node_type_fail.kdl │ ├── slashdash_after_prop_key_fail.kdl │ ├── slashdash_after_prop_val_type_fail.kdl │ ├── slashdash_after_type_fail.kdl │ ├── slashdash_arg_after_newline_esc.kdl │ ├── slashdash_arg_before_newline_esc.kdl │ ├── slashdash_before_children_end_fail.kdl │ ├── slashdash_before_eof_fail.kdl │ ├── slashdash_before_prop_value_fail.kdl │ ├── slashdash_before_semicolon_fail.kdl │ ├── slashdash_between_child_blocks_fail.kdl │ ├── slashdash_child.kdl │ ├── slashdash_child_block_before_entry_err_fail.kdl │ ├── slashdash_empty_child.kdl │ ├── slashdash_escline_before_arg_type.kdl │ ├── slashdash_escline_before_children.kdl │ ├── slashdash_escline_before_node.kdl │ ├── slashdash_false_node.kdl │ ├── slashdash_full_node.kdl │ ├── slashdash_in_slashdash.kdl │ ├── slashdash_inside_arg_type_fail.kdl │ ├── slashdash_inside_node_type_fail.kdl │ ├── slashdash_multi_line_comment_entry.kdl │ ├── slashdash_multi_line_comment_inline.kdl │ ├── slashdash_multiple_child_blocks.kdl │ ├── slashdash_negative_number.kdl │ ├── slashdash_newline_before_children.kdl │ ├── slashdash_newline_before_entry.kdl │ ├── slashdash_newline_before_node.kdl │ ├── slashdash_node_in_child.kdl │ ├── slashdash_node_with_child.kdl │ ├── slashdash_only_node.kdl │ ├── slashdash_only_node_with_space.kdl │ ├── slashdash_prop.kdl │ ├── slashdash_raw_prop_key.kdl │ ├── slashdash_repeated_prop.kdl │ ├── slashdash_single_line_comment_entry.kdl │ ├── slashdash_single_line_comment_node.kdl │ ├── space_after_arg_type.kdl │ ├── space_after_node_type.kdl │ ├── space_after_prop_type.kdl │ ├── space_around_prop_marker.kdl │ ├── space_in_arg_type.kdl │ ├── space_in_node_type.kdl │ ├── space_in_prop_type.kdl │ ├── square_bracket_in_bare_id_fail.kdl │ ├── string_arg.kdl │ ├── string_escaped_literal_whitespace.kdl │ ├── string_prop.kdl │ ├── tab_space.kdl │ ├── trailing_crlf.kdl │ ├── trailing_underscore_hex.kdl │ ├── trailing_underscore_octal.kdl │ ├── true_prefix_in_bare_id.kdl │ ├── true_prefix_in_prop_key.kdl │ ├── true_prop_key_fail.kdl │ ├── two_nodes.kdl │ ├── type_before_prop_key_fail.kdl │ ├── unbalanced_raw_hashes_fail.kdl │ ├── underscore_at_start_of_fraction_fail.kdl │ ├── underscore_at_start_of_hex_fail.kdl │ ├── underscore_before_number.kdl │ ├── underscore_in_exponent.kdl │ ├── underscore_in_float.kdl │ ├── underscore_in_fraction.kdl │ ├── underscore_in_int.kdl │ ├── underscore_in_octal.kdl │ ├── unicode_delete_fail.kdl │ ├── unicode_fsi_fail.kdl │ ├── unicode_lre_fail.kdl │ ├── unicode_lri_fail.kdl │ ├── unicode_lrm_fail.kdl │ ├── unicode_lro_fail.kdl │ ├── unicode_pdf_fail.kdl │ ├── unicode_pdi_fail.kdl │ ├── unicode_rle_fail.kdl │ ├── unicode_rli_fail.kdl │ ├── unicode_rlm_fail.kdl │ ├── unicode_rlo_fail.kdl │ ├── unicode_silly.kdl │ ├── unicode_under_0x20_fail.kdl │ ├── unterminated_empty_node_fail.kdl │ ├── unusual_bare_id_chars_in_quoted_id.kdl │ ├── unusual_chars_in_bare_id.kdl │ ├── vertical_tab_whitespace.kdl │ ├── zero_float.kdl │ ├── zero_int.kdl │ ├── zero_space_before_first_arg_fail.kdl │ ├── zero_space_before_prop_fail.kdl │ ├── zero_space_before_second_arg_fail.kdl │ └── zero_space_before_slashdash_arg_fail.kdl └── tools └── kdl-lsp ├── Cargo.toml ├── README.md └── src └── main.rs /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [zkat] 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | RUSTFLAGS: -Dwarnings 7 | 8 | jobs: 9 | fmt_and_docs: 10 | name: Check fmt & build docs 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v1 14 | - name: Install Rust 15 | uses: actions-rs/toolchain@v1 16 | with: 17 | profile: minimal 18 | toolchain: stable 19 | components: rustfmt 20 | override: true 21 | - name: rustfmt 22 | run: cargo fmt --all -- --check 23 | - name: docs 24 | run: cargo doc --no-deps 25 | 26 | build_and_test: 27 | name: Build & Test 28 | runs-on: ${{ matrix.os }} 29 | strategy: 30 | matrix: 31 | rust: [1.81, stable] 32 | os: [ubuntu-latest, macOS-latest, windows-latest] 33 | 34 | steps: 35 | - uses: actions/checkout@v1 36 | - name: Install Rust 37 | uses: actions-rs/toolchain@v1 38 | with: 39 | profile: minimal 40 | toolchain: ${{ matrix.rust }} 41 | components: clippy 42 | override: true 43 | - name: Clippy 44 | run: cargo clippy --all -- -D warnings 45 | - name: Run tests 46 | run: cargo test --features span --features v1 --all --verbose 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## When Something Happens 4 | 5 | If you see behavoir that makes you feel unsafe or unwelcome or otherwise uncomfortable, follow these steps: 6 | 7 | 1. Let the person know that what they did is not appropriate and ask them to stop and/or edit their message(s) or commits. 8 | 2. That person should immediately stop the behavior and correct the issue. 9 | 3. If this doesn’t happen, or if you're uncomfortable speaking up, [contact the maintainers](#contacting-maintainers). 10 | 4. As soon as available, a maintainer will look into the issue, and take [further action (see below)](#further-enforcement), starting with a warning, then temporary block, then long-term repo or organization ban. 11 | 12 | **The maintainer team will prioritize the well-being and comfort of those affected over the comfort of the offending party.** See [some examples below](#enforcement-examples). 13 | 14 | ## Our Pledge 15 | 16 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers of this project pledge to making participation in our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, technical preferences, nationality, personal appearance, race, religion, or sexual identity and orientation. 17 | 18 | This commitment means that inappropriate behavior can lead to intervention. This includes our intention to address issues with [missing stairs](https://en.wikipedia.org/wiki/Missing_stair) who may not have explicitly violated any written-down rules but might still be disrupting the community. 19 | 20 | ## Scope 21 | 22 | This Code of Conduct applies both within spaces involving this project and in other spaces involving community members. This includes the repository, its Pull Requests and Issue tracker, its Twitter community, private email communications in the context of the project, and any events where members of the project are participating, as well as adjacent communities and venues affecting the project's members. 23 | 24 | Depending on the violation, the maintainers may decide that violations of this code of conduct that have happened outside of the scope of the community may deem an individual unwelcome, and take appropriate action to maintain the comfort and safety of its members. 25 | 26 | ## Contacting Maintainers 27 | 28 | - [Kat Marchán ](mailto:coc@zkat.tech) 29 | 30 | ## Further Enforcement 31 | 32 | If you've already followed the [initial enforcement steps](#enforcement), these are the steps maintainers will take for further enforcement, as needed: 33 | 34 | 1. Repeat the request to stop. 35 | 2. If the person doubles down, they will have offending messages removed or edited by a maintainers given an official warning. The PR or Issue may be locked. 36 | 3. If the behavior continues or is repeated later, the person will be blocked from participating for 24 hours. 37 | 4. If the behavior continues or is repeated after the temporary block, a long-term (6-12mo) ban will be used. 38 | 39 | On top of this, maintainers may remove any offending messages, images, contributions, etc, as they deem necessary. 40 | 41 | Maintainers reserve full rights to skip any of these steps, at their discretion, if the violation is considered to be a serious and/or immediate threat to the health and well-being of members of the community. These include any threats, serious physical or verbal attacks, and other such behavior that would be completely unacceptable in any social setting that puts our members at risk. 42 | 43 | Members expelled from events or venues with any sort of paid attendance will not be refunded. 44 | 45 | ## Who Watches the Watchers? 46 | 47 | Maintainers and other leaders who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. These may include anything from removal from the maintainer team to a permanent ban from the community. 48 | 49 | Additionally, as a project hosted on both GitHub, [their Community Guidielines may be applied to maintainers of this project](https://help.github.com/articles/github-community-guidelines/), externally of this project's procedures. 50 | 51 | ## Enforcement Examples 52 | 53 | ### The Best Case 54 | 55 | The vast majority of situations work out like this. This interaction is common, and generally positive. 56 | 57 | > Alex: "Yeah I used X and it was really crazy!" 58 | 59 | > Patt (not a maintainer): "Hey, could you not use that word? What about 'ridiculous' instead?" 60 | 61 | > Alex: "oh sorry, sure." -> edits old comment to say "it was really confusing!" 62 | 63 | ### The Maintainer Case 64 | 65 | Sometimes, though, you need to get maintainers involved. Maintainers will do their best to resolve conflicts, but people who were harmed by something **will take priority**. 66 | 67 | > Patt: "Honestly, sometimes I just really hate using $library and anyone who uses it probably sucks at their job." 68 | 69 | > Alex: "Whoa there, could you dial it back a bit? There's a CoC thing about attacking folks' tech use like that." 70 | 71 | > Patt: "I'm not attacking anyone, what's your problem?" 72 | 73 | > Alex: "@maintainers hey uh. Can someone look at this issue? Patt is getting a bit aggro. I tried to nudge them about it, but nope." 74 | 75 | > KeeperOfCommitBits: (on issue) "Hey Patt, maintainer here. Could you tone it down? This sort of attack is really not okay in this space." 76 | 77 | > Patt: "Leave me alone I haven't said anything bad wtf is wrong with you." 78 | 79 | > KeeperOfCommitBits: (deletes user's comment), "@patt I mean it. Please refer to the CoC over at (URL to this CoC) if you have questions, but you can consider this an actual warning. I'd appreciate it if you reworded your messages in this thread, since they made folks there uncomfortable. Let's try and be kind, yeah?" 80 | 81 | > Patt: "@keeperofbits Okay sorry. I'm just frustrated and I'm kinda burnt out and I guess I got carried away. I'll DM Alex a note apologizing and edit my messages. Sorry for the trouble." 82 | 83 | > KeeperOfCommitBits: "@patt Thanks for that. I hear you on the stress. Burnout sucks :/. Have a good one!" 84 | 85 | ### The Nope Case 86 | 87 | > PepeTheFrog🐸: "Hi, I am a literal actual nazi and I think white supremacists are quite fashionable." 88 | 89 | > Patt: "NOOOOPE. OH NOPE NOPE." 90 | 91 | > Alex: "JFC NO. NOPE. @keeperofbits NOPE NOPE LOOK HERE" 92 | 93 | > KeeperOfCommitBits: "👀 Nope. NOPE NOPE NOPE. 🔥" 94 | 95 | > PepeTheFrog🐸 has been banned from all organization or user repositories belonging to KeeperOfCommitBits. 96 | 97 | ## Attribution 98 | 99 | This Code of Conduct was generated using [WeAllJS Code of Conduct Generator](https://npm.im/weallbehave), which is based on the [WeAllJS Code of 100 | Conduct](https://wealljs.org/code-of-conduct), which is itself based on 101 | [Contributor Covenant](http://contributor-covenant.org), version 1.4, available 102 | at 103 | [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4), 104 | and the LGBTQ in Technology Slack [Code of 105 | Conduct](http://lgbtq.technology/coc.html). 106 | 107 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kdl" 3 | version = "6.3.3" 4 | description = "Document-oriented KDL parser and API. Allows formatting/whitespace/comment-preserving parsing and modification of KDL text." 5 | authors = ["Kat Marchán ", "KDL Community"] 6 | license = "Apache-2.0" 7 | readme = "README.md" 8 | homepage = "https://kdl.dev" 9 | repository = "https://github.com/kdl-org/kdl-rs" 10 | keywords = ["kdl", "document", "serialization", "config"] 11 | rust-version = "1.81" 12 | edition = "2021" 13 | 14 | [features] 15 | default = ["span"] 16 | span = [] 17 | v1-fallback = ["v1"] 18 | v1 = ["kdlv1"] 19 | 20 | [workspace] 21 | members = ["tools/*"] 22 | 23 | [dependencies] 24 | miette.workspace = true 25 | num = "0.4.2" 26 | winnow = { version = "=0.6.24", features = ["alloc", "unstable-recover"] } 27 | kdlv1 = { package = "kdl", version = "4.7.0", optional = true } 28 | 29 | [workspace.dependencies] 30 | miette = { version = "7.6.0", default-features = false } 31 | 32 | [dev-dependencies] 33 | miette = { workspace = true, features = ["derive", "fancy"] } 34 | thiserror = "2.0.12" 35 | pretty_assertions = "1.3.0" 36 | 37 | # The profile that 'dist' will build with 38 | [profile.dist] 39 | inherits = "release" 40 | lto = "thin" 41 | 42 | # docs.rs-specific configuration 43 | [package.metadata.docs.rs] 44 | # document all features 45 | all-features = true 46 | # defines the configuration attribute `docsrs` 47 | rustdoc-args = ["--cfg", "docsrs"] 48 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | [tasks.changelog] 2 | workspace=false 3 | install_crate="git-cliff" 4 | command = "git-cliff" 5 | args = ["--prepend", "CHANGELOG.md", "-u", "--tag", "${@}"] 6 | 7 | [tasks.release] 8 | workspace=false 9 | install_crate="cargo-release" 10 | command = "cargo" 11 | args = ["release", "--workspace", "${@}"] 12 | 13 | [tasks.readme] 14 | workspace=false 15 | install_crate="cargo-readme" 16 | command = "cargo" 17 | args = ["readme", "-o", "README.md"] 18 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | kdl-rs 2 | Copyright 2020 Kat Marchán 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `kdl` 2 | 3 | `kdl` is a "document-oriented" parser and API for the [KDL Document 4 | Language](https://kdl.dev), a node-based, human-friendly configuration and 5 | serialization format. 6 | 7 | Unlike serde-based implementations, this crate preserves formatting when 8 | editing, as well as when inserting or changing values with custom 9 | formatting. This is most useful when working with human-maintained KDL 10 | files. 11 | 12 | You can think of this crate as 13 | [`toml_edit`](https://crates.io/crates/toml_edit), but for KDL. 14 | 15 | This crate supports both KDL v2.0.0 and v1.0.0 (when using the non-default 16 | `v1` feature). It also supports converting documents between either format. 17 | 18 | There is also a `v1-fallback` feature that may be enabled in order to have 19 | the various `Kdl*::parse` methods try to parse their input as v2, and, if 20 | that fails, try again as v1. In either case, a dedicated `Kdl*::parse_v1` 21 | method is available for v1-exclusive parsing, as long as either `v1` or 22 | `v1-fallback` are enabled. 23 | 24 | ### Example 25 | 26 | ```rust 27 | use kdl::{KdlDocument, KdlValue}; 28 | 29 | let doc_str = r#" 30 | hello 1 2 3 31 | 32 | // Comment 33 | world prop=string-value { 34 | child 1 35 | child 2 36 | child #inf 37 | } 38 | "#; 39 | 40 | let doc: KdlDocument = doc_str.parse().expect("failed to parse KDL"); 41 | 42 | assert_eq!( 43 | doc.iter_args("hello").collect::>(), 44 | vec![&1.into(), &2.into(), &3.into()] 45 | ); 46 | 47 | assert_eq!( 48 | doc.get("world").map(|node| &node["prop"]), 49 | Some(&"string-value".into()) 50 | ); 51 | 52 | // Documents fully roundtrip: 53 | assert_eq!(doc.to_string(), doc_str); 54 | ``` 55 | 56 | ### Controlling Formatting 57 | 58 | By default, everything is created with default formatting. You can parse 59 | items manually to provide custom representations, comments, etc: 60 | 61 | ```rust 62 | let node_str = r#" 63 | // indented comment 64 | "formatted" 1 /* comment */ \ 65 | 2; 66 | "#; 67 | 68 | let mut doc = kdl::KdlDocument::new(); 69 | doc.nodes_mut().push(node_str.parse().unwrap()); 70 | 71 | assert_eq!(&doc.to_string(), node_str); 72 | ``` 73 | 74 | [`KdlDocument`], [`KdlNode`], [`KdlEntry`], and [`KdlIdentifier`] can all 75 | be parsed and managed this way. 76 | 77 | ### Error Reporting 78 | 79 | [`KdlError`] implements [`miette::Diagnostic`] and can be used to display 80 | detailed, pretty-printed diagnostic messages when using [`miette::Result`] 81 | and the `"fancy"` feature flag for `miette`: 82 | 83 | ```toml 84 | # Cargo.toml 85 | [dependencies] 86 | miette = { version = "x.y.z", features = ["fancy"] } 87 | ``` 88 | 89 | ```rust 90 | fn main() -> miette::Result<()> { 91 | "foo 1.".parse::()?; 92 | Ok(()) 93 | } 94 | ``` 95 | 96 | This will display a message like: 97 | ``` 98 | Error: 99 | × Expected valid value. 100 | ╭──── 101 | 1 │ foo 1. 102 | · ─┬ 103 | · ╰── invalid float 104 | ╰──── 105 | help: Floating point numbers must be base 10, and have numbers after the decimal point. 106 | ``` 107 | 108 | ### Features 109 | 110 | * `span` (default) - Includes spans in the various document-related structs. 111 | * `v1` - Adds support for v1 parsing. This will pull in the entire previous 112 | version of `kdl-rs`, and so may be fairly heavy. 113 | * `v1-fallback` - Implies `v1`. Makes it so the various `*::parse()` and 114 | `FromStr` implementations try to parse their inputs as `v2`, and, if that 115 | fails, try again with `v1`. For `KdlDocument`, a heuristic will be applied 116 | if both `v1` and `v2` parsers fail, to pick which error(s) to return. For 117 | other types, only the `v2` parser's errors will be returned. 118 | 119 | ### Quirks 120 | 121 | #### Properties 122 | 123 | Multiple properties with the same name are allowed, and all duplicated 124 | **will be preserved**, meaning those documents will correctly round-trip. 125 | When using `node.get()`/`node["key"]` & company, the _last_ property with 126 | that name's value will be returned (as per spec). 127 | 128 | #### Numbers 129 | 130 | KDL itself does not specify a particular representation for numbers and 131 | accepts just about anything valid, no matter how large and how small. This 132 | means a few things: 133 | 134 | * Numbers without a decimal point are interpreted as [`i128`]. 135 | * Numbers with a decimal point are interpreted as [`f64`]. 136 | * The keywords `#inf`, `#-inf`, and `#nan` evaluate to [`f64::INFINITY`], 137 | [`f64::NEG_INFINITY`], and [`f64::NAN`]. 138 | * The original _representation/text_ of these numbers will be preserved, 139 | unless you [`KdlDocument::autoformat`] in which case the original 140 | representation will be thrown away and the actual value will be used when 141 | serializing. 142 | 143 | ### Minimum Supported Rust Version (MSRV) 144 | 145 | You must be at least `1.81` tall to get on this ride. 146 | 147 | ### License 148 | 149 | The code in this repository is covered by [the Apache-2.0 150 | License](./LICENSE). 151 | 152 | [`KdlDocument`]: https://docs.rs/kdl/latest/kdl/struct.KdlDocument.html 153 | [`KdlNode`]: https://docs.rs/kdl/latest/kdl/struct.KdlNode.html 154 | [`KdlEntry`]: https://docs.rs/kdl/latest/kdl/struct.KdlEntry.html 155 | [`KdlIdentifier`]: https://docs.rs/kdl/latest/kdl/struct.KdlIdentifier.html 156 | [`KdlError`]: https://docs.rs/kdl/latest/kdl/struct.KdlError.html 157 | [`miette::Diagnostic`]: https://docs.rs/miette/latest/miette/trait.Diagnostic.html 158 | [`miette::Result`]: https://docs.rs/miette/latest/miette/type.Result.html 159 | -------------------------------------------------------------------------------- /README.tpl: -------------------------------------------------------------------------------- 1 | # `{{crate}}` 2 | 3 | {{readme}} 4 | 5 | [`KdlDocument`]: https://docs.rs/kdl/latest/kdl/struct.KdlDocument.html 6 | [`KdlNode`]: https://docs.rs/kdl/latest/kdl/struct.KdlNode.html 7 | [`KdlEntry`]: https://docs.rs/kdl/latest/kdl/struct.KdlEntry.html 8 | [`KdlIdentifier`]: https://docs.rs/kdl/latest/kdl/struct.KdlIdentifier.html 9 | [`KdlError`]: https://docs.rs/kdl/latest/kdl/struct.KdlError.html 10 | [`miette::Diagnostic`]: https://docs.rs/miette/latest/miette/trait.Diagnostic.html 11 | [`miette::Result`]: https://docs.rs/miette/latest/miette/type.Result.html 12 | -------------------------------------------------------------------------------- /cliff.toml: -------------------------------------------------------------------------------- 1 | # configuration file for git-cliff (0.1.0) 2 | 3 | [changelog] 4 | # changelog header 5 | header = """ 6 | # `kdl` Release Changelog 7 | 8 | """ 9 | 10 | # template for the changelog body 11 | # https://tera.netlify.app/docs/#introduction 12 | body = """ 13 | {% if version %}\ 14 | 15 | ## {{ version | replace(from="v", to="") }} ({{ timestamp | date(format="%Y-%m-%d") }}) 16 | {% else %}\ 17 | ## Unreleased 18 | {% endif %}\ 19 | {% for group, commits in commits | filter(attribute="scope") | group_by(attribute="group") %} 20 | ### {{ group | upper_first }} 21 | {% for commit in commits %} 22 | {% if commit.scope %}\ 23 | * **{{ commit.scope }}:** {{ commit.message }} ([{{ commit.id | truncate(length=8, end="") }}](https://github.com/kdl-org/kdl-rs/commit/{{ commit.id }})) 24 | {%- if commit.breaking %} 25 | * **BREAKING CHANGE**: {{ commit.breaking_description }} 26 | {%- endif %}\ 27 | {% endif %}\ 28 | {% endfor %} 29 | {% endfor %} 30 | """ 31 | 32 | # remove the leading and trailing whitespace from the template 33 | trim = false 34 | 35 | # changelog footer 36 | # footer = """ 37 | # 38 | # """ 39 | 40 | [git] 41 | # allow only conventional commits 42 | # https://www.conventionalcommits.org 43 | conventional_commits = true 44 | # regex for parsing and grouping commits 45 | commit_parsers = [ 46 | { message = "^feat*", group = "Features"}, 47 | { message = "^fix*", group = "Bug Fixes"}, 48 | { message = "^doc*", group = "Documentation"}, 49 | { message = "^perf*", group = "Performance"}, 50 | { message = "^refactor*", group = "Refactor"}, 51 | { message = "^style*", group = "Styling"}, 52 | { message = "^test*", group = "Testing"}, 53 | { message = "^chore\\(release\\): prepare for*", skip = true}, 54 | { message = "^chore*", group = "Miscellaneous Tasks"}, 55 | { body = ".*security", group = "Security"}, 56 | ] 57 | # filter out the commits that are not matched by commit parsers 58 | filter_commits = true 59 | # glob pattern for matching git tags 60 | # tag_pattern = "v?[0-9]*" 61 | # regex for skipping tags 62 | # skip_tags = "v0.1.0-beta.1" 63 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | msrv = "1.71.1" 2 | -------------------------------------------------------------------------------- /dist-workspace.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["cargo:tools/kdl-lsp"] 3 | 4 | # Config for 'dist' 5 | [dist] 6 | # The preferred dist version to use in CI (Cargo.toml SemVer syntax) 7 | cargo-dist-version = "0.28.0" 8 | # CI backends to support 9 | ci = "github" 10 | # The installers to generate for each app 11 | installers = ["shell", "powershell", "npm"] 12 | # Target platforms to build apps for (Rust target-triple syntax) 13 | targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "aarch64-pc-windows-msvc", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] 14 | # Path that installers should place binaries in 15 | install-path = "CARGO_HOME" 16 | # Whether to install an updater program 17 | install-updater = false 18 | # Publish jobs to run in CI 19 | publish-jobs = ["npm"] 20 | 21 | [dist.github-custom-runners] 22 | global = "ubuntu-22.04" 23 | -------------------------------------------------------------------------------- /examples/Cargo.kdl: -------------------------------------------------------------------------------- 1 | package { 2 | name kdl 3 | version "0.0.0" 4 | description "The kdl document language" 5 | authors "Kat Marchán " 6 | license-file LICENSE 7 | edition "2018" 8 | } 9 | 10 | dependencies { 11 | nom "6.0.1" 12 | thiserror "1.0.22" 13 | } 14 | -------------------------------------------------------------------------------- /examples/ci.kdl: -------------------------------------------------------------------------------- 1 | // This example is a GitHub Action if it used KDL syntax. 2 | // See .github/workflows/ci.yml for the file this was based on. 3 | name CI 4 | 5 | on push pull_request 6 | 7 | env { 8 | RUSTFLAGS -Dwarnings 9 | } 10 | 11 | jobs { 12 | fmt_and_docs "Check fmt & build docs" { 13 | runs-on ubuntu-latest 14 | steps { 15 | step uses="actions/checkout@v1" 16 | step "Install Rust" uses="actions-rs/toolchain@v1" { 17 | profile minimal 18 | toolchain stable 19 | components rustfmt 20 | override #true 21 | } 22 | step rustfmt { run cargo fmt --all -- --check } 23 | step docs { run cargo doc --no-deps } 24 | } 25 | } 26 | build_and_test "Build & Test" { 27 | runs-on "${{ matrix.os }}" 28 | strategy { 29 | matrix { 30 | rust "1.46.0" stable 31 | os ubuntu-latest macOS-latest windows-latest 32 | } 33 | } 34 | 35 | steps { 36 | step uses="actions/checkout@v1" 37 | step "Install Rust" uses="actions-rs/toolchain@v1" { 38 | profile minimal 39 | toolchain "${{ matrix.rust }}" 40 | components clippy 41 | override #true 42 | } 43 | step Clippy { run cargo clippy --all -- -D warnings } 44 | step "Run tests" { run cargo test --all --verbose } 45 | step "Other Stuff" run=""" 46 | echo foo 47 | echo bar 48 | echo baz 49 | """ 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/custom-errors.rs: -------------------------------------------------------------------------------- 1 | // TODO(@zkat): Error stuff has changed, so this needs updating. 2 | 3 | // /// Show how to build your own diagnostics, without having to use the 4 | // /// `fancy` feature or having `main()` return `miette::Result` 5 | // /// 6 | // use kdl::KdlDocument; 7 | // use miette::Diagnostic; 8 | // use miette::SourceSpan; 9 | 10 | // #[derive(Debug)] 11 | // pub struct MyError { 12 | // pub message: String, 13 | // } 14 | 15 | // fn parse(input: &str) -> Result { 16 | // let doc = input.parse::(); 17 | // doc.map_err(|error| { 18 | // let source = error 19 | // .source_code() 20 | // .expect("parse errors should have source code"); 21 | // let help = error.help.unwrap_or_default(); 22 | // let span: SourceSpan = error.span; 23 | // let contents = source 24 | // .read_span(&span, 0, 0) 25 | // .expect("source should have span contents"); 26 | // // miette uses 0 based indexes, but humans prefer 1-based 27 | // let line = contents.line() + 1; 28 | // let column = contents.column() + 1; 29 | // let message = format!( 30 | // "line {}, column {}: {}\n help: {}", 31 | // line, column, error, help 32 | // ); 33 | // MyError { message } 34 | // }) 35 | // } 36 | 37 | fn main() { 38 | // let input = r#" 39 | // foo { 40 | // bar { 41 | // baz 1. 42 | // } 43 | // } 44 | // "#; 45 | // let err = parse(input).unwrap_err(); 46 | // eprintln!("{}", err.message); 47 | // // Output: 48 | // // line 4, column 14: Expected valid value. 49 | // // help: Floating point numbers must be base 10, and have numbers after the decimal point. 50 | } 51 | -------------------------------------------------------------------------------- /examples/insert-node.rs: -------------------------------------------------------------------------------- 1 | // Shows how to maintain nodes sorted by value in a 2 | // machine-generated kdl document 3 | 4 | use kdl::{KdlDocument, KdlIdentifier, KdlNode}; 5 | 6 | fn sort_by_name(x: &KdlNode, y: &KdlNode) -> std::cmp::Ordering { 7 | x.name().value().cmp(y.name().value()) 8 | } 9 | 10 | fn main() -> miette::Result<()> { 11 | let input = r#" 12 | words { 13 | apple // one a day keeps the doctor away 14 | orange 15 | } 16 | "#; 17 | let mut doc: KdlDocument = input.parse()?; 18 | 19 | let words_section = doc.get_mut("words").expect("'words' section should exist"); 20 | let children = words_section 21 | .children_mut() 22 | .as_mut() 23 | .expect("'words' section should have children"); 24 | let word_nodes = children.nodes_mut(); 25 | 26 | let identifier = KdlIdentifier::from("banana"); 27 | let word_node = KdlNode::new(identifier); 28 | word_nodes.push(word_node); 29 | word_nodes.sort_by(sort_by_name); 30 | words_section.autoformat(); 31 | 32 | println!("{}", doc); 33 | 34 | // output: 35 | // words { 36 | // apple // one a day keeps the doctor away 37 | // banana 38 | // orange 39 | // } 40 | 41 | Ok(()) 42 | } 43 | -------------------------------------------------------------------------------- /examples/website.kdl: -------------------------------------------------------------------------------- 1 | !doctype html 2 | html lang=en { 3 | head { 4 | meta charset=utf-8 5 | meta name=viewport content="width=device-width, initial-scale=1.0" 6 | meta \ 7 | name=description \ 8 | content="kdl is a document language, mostly based on SDLang, with xml-like semantics that looks like you're invoking a bunch of CLI commands!" 9 | title "kdl - The KDL Document Language" 10 | link rel=stylesheet href="/styles/global.css" 11 | } 12 | body { 13 | main { 14 | header class="py-10 bg-gray-300" { 15 | h1 class="text-4xl text-center" "kdl - The KDL Document Language" 16 | } 17 | section class=kdl-section id=description { 18 | p { 19 | - "kdl is a document language, mostly based on " 20 | a href="https://sdlang.org" "SDLang" 21 | - " with xml-like semantics that looks like you're invoking a bunch of CLI commands" 22 | } 23 | p "It's meant to be used both as a serialization format and a configuration language, and is relatively light on syntax compared to XML." 24 | } 25 | section class=kdl-section id=design-and-discussion { 26 | h2 "Design and Discussion" 27 | p { 28 | - "kdl is still extremely new, and discussion about the format should happen over on the " 29 | a href="https://github.com/kdoclang/kdl/discussions" { 30 | - "discussions" 31 | } 32 | - " page in the Github repo. Feel free to jump in and give us your 2 cents!" 33 | } 34 | } 35 | section class=kdl-section id=design-principles { 36 | h2 "Design Principles" 37 | ol { 38 | li Maintainability 39 | li Flexibility 40 | li "Cognitive simplicity and Learnability" 41 | li "Ease of de/serialization" 42 | li "Ease of implementation" 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt::Display, iter, sync::Arc}; 2 | 3 | use miette::{Diagnostic, LabeledSpan, Severity, SourceSpan}; 4 | 5 | #[cfg(doc)] 6 | use { 7 | crate::KdlNode, 8 | std::convert::{TryFrom, TryInto}, 9 | }; 10 | 11 | /// The toplevel `Error` type for KDL: this is returned when a KDL document 12 | /// failed to parse entirely. 13 | /// 14 | /// This diagnostic implements [`miette::Diagnostic`] and can be used to 15 | /// display detailed, pretty-printed diagnostic messages when using 16 | /// [`miette::Result`] and the `"fancy"` feature flag for `miette`: 17 | /// 18 | /// ```no_run 19 | /// fn main() -> miette::Result<()> { 20 | /// "foo 1.".parse::()?; 21 | /// Ok(()) 22 | /// } 23 | /// ``` 24 | /// 25 | /// This will display a message like: 26 | /// ```text 27 | /// Error: 28 | /// × Expected valid value. 29 | /// ╭──── 30 | /// 1 │ foo 1. 31 | /// · ─┬ 32 | /// · ╰── invalid float 33 | /// ╰──── 34 | /// help: Floating point numbers must be base 10, and have numbers after the decimal point. 35 | /// ``` 36 | #[derive(Debug, Clone, Eq, PartialEq)] 37 | pub struct KdlError { 38 | /// Original input that this failure came from. 39 | pub input: Arc, 40 | 41 | /// Sub-diagnostics for this failure. 42 | pub diagnostics: Vec, 43 | } 44 | 45 | impl Display for KdlError { 46 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 47 | write!(f, "Failed to parse KDL document") 48 | } 49 | } 50 | impl Error for KdlError {} 51 | 52 | impl Diagnostic for KdlError { 53 | fn source_code(&self) -> Option<&dyn miette::SourceCode> { 54 | Some(&self.input) 55 | } 56 | 57 | fn related<'a>(&'a self) -> Option + 'a>> { 58 | Some(Box::new( 59 | self.diagnostics.iter().map(|d| d as &dyn Diagnostic), 60 | )) 61 | } 62 | } 63 | 64 | /// An individual diagnostic message for a KDL parsing issue. 65 | /// 66 | /// While generally signifying errors, they can also be treated as warnings. 67 | #[derive(Debug, Clone, Eq, PartialEq)] 68 | pub struct KdlDiagnostic { 69 | /// Shared source for the diagnostic. 70 | pub input: Arc, 71 | 72 | /// Offset in chars of the error. 73 | pub span: SourceSpan, 74 | 75 | /// Message for the error itself. 76 | pub message: Option, 77 | 78 | /// Label text for this span. Defaults to `"here"`. 79 | pub label: Option, 80 | 81 | /// Suggestion for fixing the parser error. 82 | pub help: Option, 83 | 84 | /// Severity level for the Diagnostic. 85 | pub severity: Severity, 86 | } 87 | 88 | impl Display for KdlDiagnostic { 89 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 90 | let message = self 91 | .message 92 | .clone() 93 | .unwrap_or_else(|| "Unexpected error".into()); 94 | write!(f, "{message}") 95 | } 96 | } 97 | impl Error for KdlDiagnostic {} 98 | 99 | impl Diagnostic for KdlDiagnostic { 100 | fn source_code(&self) -> Option<&dyn miette::SourceCode> { 101 | Some(&self.input) 102 | } 103 | 104 | fn severity(&self) -> Option { 105 | Some(self.severity) 106 | } 107 | 108 | fn help<'a>(&'a self) -> Option> { 109 | self.help.as_ref().map(|s| Box::new(s) as Box) 110 | } 111 | 112 | fn labels(&self) -> Option + '_>> { 113 | let label = self.label.clone().unwrap_or_else(|| "here".to_owned()); 114 | let labeled_span = LabeledSpan::new_with_span(Some(label), self.span); 115 | 116 | Some(Box::new(iter::once(labeled_span))) 117 | } 118 | } 119 | 120 | #[cfg(feature = "v1")] 121 | impl From for KdlError { 122 | fn from(value: kdlv1::KdlError) -> Self { 123 | let input = Arc::new(value.input); 124 | KdlError { 125 | input: input.clone(), 126 | diagnostics: vec![KdlDiagnostic { 127 | input, 128 | span: SourceSpan::new(value.span.offset().into(), value.span.len()), 129 | message: Some(format!("{}", value.kind)), 130 | label: value.label.map(|x| x.into()), 131 | help: value.help.map(|x| x.into()), 132 | severity: Severity::Error, 133 | }], 134 | } 135 | } 136 | } 137 | 138 | #[cfg(test)] 139 | mod tests { 140 | use super::*; 141 | 142 | #[test] 143 | fn kdl_error() { 144 | let kdl_diagnostic = KdlDiagnostic { 145 | input: Default::default(), 146 | span: SourceSpan::new(0.into(), 0), 147 | message: Default::default(), 148 | label: Default::default(), 149 | help: Default::default(), 150 | severity: Default::default(), 151 | }; 152 | 153 | let kdl_error = KdlError { 154 | input: Arc::new("bark? i guess?".to_owned()), 155 | diagnostics: vec![kdl_diagnostic.clone(), kdl_diagnostic], 156 | }; 157 | 158 | // Test `Error` impl 159 | assert_eq!(kdl_error.to_string(), "Failed to parse KDL document"); 160 | assert!(kdl_error.source().is_none()); 161 | 162 | // Test `Diagnostic` impl 163 | let related: Vec<_> = kdl_error.related().unwrap().collect(); 164 | assert_eq!(related.len(), 2); 165 | assert_eq!( 166 | kdl_error 167 | .source_code() 168 | .unwrap() 169 | .read_span(&SourceSpan::new(0.into(), 5), 0, 0) 170 | .unwrap() 171 | .data(), 172 | b"bark?" 173 | ); 174 | } 175 | 176 | #[test] 177 | fn kdl_diagnostic() { 178 | let mut kdl_diagnostic = KdlDiagnostic { 179 | input: Arc::new("Catastrophic failure!!!".to_owned()), 180 | span: SourceSpan::new(0.into(), 3), 181 | message: None, 182 | label: Some("cute".to_owned()), 183 | help: Some("try harder?".to_owned()), 184 | severity: Severity::Error, 185 | }; 186 | 187 | // Test `Error` impl 188 | assert_eq!(kdl_diagnostic.to_string(), "Unexpected error"); 189 | assert!(kdl_diagnostic.source().is_none()); 190 | 191 | kdl_diagnostic.message = Some("mega bad news, kiddo".to_owned()); 192 | 193 | assert_eq!(kdl_diagnostic.to_string(), "mega bad news, kiddo"); 194 | assert!(kdl_diagnostic.source().is_none()); 195 | 196 | // Test `Diagnostic` impl 197 | let labels: Vec<_> = kdl_diagnostic.labels().unwrap().collect(); 198 | assert_eq!(labels.len(), 1); 199 | assert_eq!(labels[0].label().unwrap(), "cute"); 200 | assert_eq!( 201 | kdl_diagnostic 202 | .source_code() 203 | .unwrap() 204 | .read_span(labels[0].inner(), 0, 0) 205 | .unwrap() 206 | .data(), 207 | b"Cat" 208 | ); 209 | assert_eq!(kdl_diagnostic.help().unwrap().to_string(), "try harder?"); 210 | assert_eq!(kdl_diagnostic.severity().unwrap(), Severity::Error); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/fmt.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Write as _; 2 | 3 | /// Formatting configuration for use with [`KdlDocument::autoformat_config`](`crate::KdlDocument::autoformat_config`) 4 | /// and [`KdlNode::autoformat_config`](`crate::KdlNode::autoformat_config`). 5 | #[non_exhaustive] 6 | #[derive(Debug)] 7 | pub struct FormatConfig<'a> { 8 | /// How deeply to indent the overall node or document, 9 | /// in repetitions of [`indent`](`FormatConfig::indent`). 10 | /// Defaults to `0`. 11 | pub indent_level: usize, 12 | 13 | /// The indentation to use at each level. Defaults to four spaces. 14 | pub indent: &'a str, 15 | 16 | /// Whether to remove comments. Defaults to `false`. 17 | pub no_comments: bool, 18 | 19 | /// Whether to keep individual entry formatting. 20 | pub entry_autoformate_keep: bool, 21 | } 22 | 23 | /// See field documentation for defaults. 24 | impl Default for FormatConfig<'_> { 25 | fn default() -> Self { 26 | Self::builder().build() 27 | } 28 | } 29 | 30 | impl FormatConfig<'_> { 31 | /// Creates a new [`FormatConfigBuilder`] with default configuration. 32 | pub const fn builder() -> FormatConfigBuilder<'static> { 33 | FormatConfigBuilder::new() 34 | } 35 | } 36 | 37 | /// A [`FormatConfig`] builder. 38 | /// 39 | /// Note that setters can be repeated. 40 | #[derive(Debug, Default)] 41 | pub struct FormatConfigBuilder<'a>(FormatConfig<'a>); 42 | 43 | impl<'a> FormatConfigBuilder<'a> { 44 | /// Creates a new [`FormatConfig`] builder with default configuration. 45 | pub const fn new() -> Self { 46 | FormatConfigBuilder(FormatConfig { 47 | indent_level: 0, 48 | indent: " ", 49 | no_comments: false, 50 | entry_autoformate_keep: false, 51 | }) 52 | } 53 | 54 | /// How deeply to indent the overall node or document, 55 | /// in repetitions of [`indent`](`FormatConfig::indent`). 56 | /// Defaults to `0` iff not specified. 57 | pub const fn maybe_indent_level(mut self, indent_level: Option) -> Self { 58 | if let Some(indent_level) = indent_level { 59 | self.0.indent_level = indent_level; 60 | } 61 | self 62 | } 63 | 64 | /// How deeply to indent the overall node or document, 65 | /// in repetitions of [`indent`](`FormatConfig::indent`). 66 | /// Defaults to `0` iff not specified. 67 | pub const fn indent_level(mut self, indent_level: usize) -> Self { 68 | self.0.indent_level = indent_level; 69 | self 70 | } 71 | 72 | /// The indentation to use at each level. 73 | /// Defaults to four spaces iff not specified. 74 | pub const fn maybe_indent<'b, 'c>(self, indent: Option<&'b str>) -> FormatConfigBuilder<'c> 75 | where 76 | 'a: 'b, 77 | 'b: 'c, 78 | { 79 | if let Some(indent) = indent { 80 | self.indent(indent) 81 | } else { 82 | self 83 | } 84 | } 85 | 86 | /// The indentation to use at each level. 87 | /// Defaults to four spaces if not specified. 88 | pub const fn indent(self, indent: &str) -> FormatConfigBuilder<'_> { 89 | FormatConfigBuilder(FormatConfig { indent, ..self.0 }) 90 | } 91 | 92 | /// Whether to remove comments. 93 | /// Defaults to `false` iff not specified. 94 | pub const fn maybe_no_comments(mut self, no_comments: Option) -> Self { 95 | if let Some(no_comments) = no_comments { 96 | self.0.no_comments = no_comments; 97 | } 98 | self 99 | } 100 | 101 | /// Whether to remove comments. 102 | /// Defaults to `false` iff not specified. 103 | pub const fn no_comments(mut self, no_comments: bool) -> Self { 104 | self.0.no_comments = no_comments; 105 | self 106 | } 107 | 108 | /// Builds the [`FormatConfig`]. 109 | pub const fn build(self) -> FormatConfig<'a> { 110 | self.0 111 | } 112 | } 113 | 114 | pub(crate) fn autoformat_leading(leading: &mut String, config: &FormatConfig<'_>) { 115 | let mut result = String::new(); 116 | if !config.no_comments { 117 | let input = leading.trim(); 118 | if !input.is_empty() { 119 | for line in input.lines() { 120 | let trimmed = line.trim(); 121 | if !trimmed.is_empty() { 122 | for _ in 0..config.indent_level { 123 | result.push_str(config.indent); 124 | } 125 | writeln!(result, "{}", trimmed).unwrap(); 126 | } 127 | } 128 | } 129 | } 130 | for _ in 0..config.indent_level { 131 | result.push_str(config.indent); 132 | } 133 | *leading = result; 134 | } 135 | 136 | pub(crate) fn autoformat_trailing(decor: &mut String, no_comments: bool) { 137 | if decor.is_empty() { 138 | return; 139 | } 140 | *decor = decor.trim().to_string(); 141 | let mut result = String::new(); 142 | if !decor.is_empty() && !no_comments { 143 | if decor.trim_start() == &decor[..] { 144 | write!(result, " ").unwrap(); 145 | } 146 | for comment in decor.lines() { 147 | writeln!(result, "{comment}").unwrap(); 148 | } 149 | } 150 | *decor = result; 151 | } 152 | 153 | #[cfg(test)] 154 | mod test { 155 | use super::*; 156 | 157 | #[test] 158 | fn builder() -> miette::Result<()> { 159 | let built = FormatConfig::builder() 160 | .indent_level(12) 161 | .indent(" \t") 162 | .no_comments(true) 163 | .build(); 164 | assert!(matches!( 165 | built, 166 | FormatConfig { 167 | indent_level: 12, 168 | indent: " \t", 169 | no_comments: true, 170 | entry_autoformate_keep: false, 171 | } 172 | )); 173 | Ok(()) 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/identifier.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "span")] 2 | use miette::SourceSpan; 3 | use std::{fmt::Display, str::FromStr}; 4 | 5 | use crate::{v2_parser, KdlError, KdlValue}; 6 | 7 | /// Represents a KDL 8 | /// [Identifier](https://github.com/kdl-org/kdl/blob/main/SPEC.md#identifier). 9 | #[derive(Debug, Clone, Eq)] 10 | pub struct KdlIdentifier { 11 | pub(crate) value: String, 12 | pub(crate) repr: Option, 13 | #[cfg(feature = "span")] 14 | pub(crate) span: SourceSpan, 15 | } 16 | 17 | impl PartialEq for KdlIdentifier { 18 | fn eq(&self, other: &Self) -> bool { 19 | self.value == other.value && self.repr == other.repr 20 | // intentionally omitted: self.span == other.span 21 | } 22 | } 23 | 24 | impl std::hash::Hash for KdlIdentifier { 25 | fn hash(&self, state: &mut H) { 26 | self.value.hash(state); 27 | self.repr.hash(state); 28 | // Intentionally omitted: self.span.hash(state); 29 | } 30 | } 31 | 32 | impl KdlIdentifier { 33 | /// Gets the string value for this identifier. 34 | pub fn value(&self) -> &str { 35 | &self.value 36 | } 37 | 38 | /// Sets the string value for this identifier. 39 | pub fn set_value(&mut self, value: impl Into) { 40 | self.value = value.into(); 41 | } 42 | 43 | /// Gets this identifier's span. 44 | /// 45 | /// This value will be properly initialized when created via [`crate::KdlDocument::parse`] 46 | /// but may become invalidated if the document is mutated. We do not currently 47 | /// guarantee this to yield any particularly consistent results at that point. 48 | #[cfg(feature = "span")] 49 | pub fn span(&self) -> SourceSpan { 50 | self.span 51 | } 52 | 53 | /// Sets this identifier's span. 54 | #[cfg(feature = "span")] 55 | pub fn set_span(&mut self, span: impl Into) { 56 | self.span = span.into(); 57 | } 58 | 59 | /// Gets the custom string representation for this identifier, if any. 60 | pub fn repr(&self) -> Option<&str> { 61 | self.repr.as_deref() 62 | } 63 | 64 | /// Sets a custom string representation for this identifier. 65 | pub fn set_repr(&mut self, repr: impl Into) { 66 | self.repr = Some(repr.into()); 67 | } 68 | 69 | /// Length of this identifier when rendered as a string. 70 | pub fn len(&self) -> usize { 71 | format!("{}", self).len() 72 | } 73 | 74 | /// Returns true if this identifier is completely empty. 75 | pub fn is_empty(&self) -> bool { 76 | self.len() == 0 77 | } 78 | 79 | /// Resets this identifier to its default representation. It will attempt 80 | /// to make it an unquoted identifier, and fall back to a string 81 | /// representation if that would be invalid. 82 | pub fn clear_format(&mut self) { 83 | self.repr = None; 84 | } 85 | 86 | /// Auto-formats this identifier. 87 | pub fn autoformat(&mut self) { 88 | self.repr = None; 89 | } 90 | 91 | /// Parses a string into a entry. 92 | /// 93 | /// If the `v1-fallback` feature is enabled, this method will first try to 94 | /// parse the string as a KDL v2 entry, and, if that fails, it will try 95 | /// to parse again as a KDL v1 entry. If both fail, only the v2 parse 96 | /// errors will be returned. 97 | pub fn parse(s: &str) -> Result { 98 | #[cfg(not(feature = "v1-fallback"))] 99 | { 100 | v2_parser::try_parse(v2_parser::identifier, s) 101 | } 102 | #[cfg(feature = "v1-fallback")] 103 | { 104 | v2_parser::try_parse(v2_parser::identifier, s) 105 | .or_else(|e| KdlIdentifier::parse_v1(s).map_err(|_| e)) 106 | } 107 | } 108 | 109 | /// Parses a KDL v1 string into an entry. 110 | #[cfg(feature = "v1")] 111 | pub fn parse_v1(s: &str) -> Result { 112 | let ret: Result = s.parse(); 113 | ret.map(|x| x.into()).map_err(|e| e.into()) 114 | } 115 | } 116 | 117 | #[cfg(feature = "v1")] 118 | impl From for KdlIdentifier { 119 | fn from(value: kdlv1::KdlIdentifier) -> Self { 120 | KdlIdentifier { 121 | value: value.value().into(), 122 | repr: value.repr().map(|x| x.into()), 123 | #[cfg(feature = "span")] 124 | span: (value.span().offset(), value.span().len()).into(), 125 | } 126 | } 127 | } 128 | 129 | impl Display for KdlIdentifier { 130 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 131 | if let Some(repr) = &self.repr { 132 | write!(f, "{}", repr) 133 | } else { 134 | write!(f, "{}", KdlValue::String(self.value().into())) 135 | } 136 | } 137 | } 138 | 139 | impl From<&str> for KdlIdentifier { 140 | fn from(value: &str) -> Self { 141 | KdlIdentifier { 142 | value: value.to_string(), 143 | repr: None, 144 | #[cfg(feature = "span")] 145 | span: SourceSpan::from(0..0), 146 | } 147 | } 148 | } 149 | 150 | impl From for KdlIdentifier { 151 | fn from(value: String) -> Self { 152 | KdlIdentifier { 153 | value, 154 | repr: None, 155 | #[cfg(feature = "span")] 156 | span: SourceSpan::from(0..0), 157 | } 158 | } 159 | } 160 | 161 | impl From for String { 162 | fn from(value: KdlIdentifier) -> Self { 163 | value.value 164 | } 165 | } 166 | 167 | impl FromStr for KdlIdentifier { 168 | type Err = KdlError; 169 | 170 | fn from_str(s: &str) -> Result { 171 | KdlIdentifier::parse(s) 172 | } 173 | } 174 | 175 | #[cfg(test)] 176 | mod test { 177 | use super::*; 178 | 179 | #[test] 180 | fn parsing() -> miette::Result<()> { 181 | let plain = "foo"; 182 | assert_eq!( 183 | plain.parse::()?, 184 | KdlIdentifier { 185 | value: plain.to_string(), 186 | repr: Some(plain.to_string()), 187 | #[cfg(feature = "span")] 188 | span: SourceSpan::from(0..3), 189 | } 190 | ); 191 | 192 | let quoted = r#""foo\"bar""#; 193 | assert_eq!( 194 | quoted.parse::()?, 195 | KdlIdentifier { 196 | value: "foo\"bar".to_string(), 197 | repr: Some(quoted.to_string()), 198 | #[cfg(feature = "span")] 199 | span: SourceSpan::from(0..0), 200 | } 201 | ); 202 | 203 | let invalid = "123"; 204 | assert!(invalid.parse::().is_err()); 205 | 206 | let invalid = " space "; 207 | assert!(invalid.parse::().is_err()); 208 | 209 | let invalid = "\"x"; 210 | assert!(invalid.parse::().is_err()); 211 | 212 | Ok(()) 213 | } 214 | 215 | #[test] 216 | fn formatting() { 217 | let plain = KdlIdentifier::from("foo"); 218 | assert_eq!(format!("{}", plain), "foo"); 219 | 220 | let quoted = KdlIdentifier::from("foo\"bar"); 221 | assert_eq!(format!("{}", quoted), r#""foo\"bar""#); 222 | 223 | let mut custom_repr = KdlIdentifier::from("foo"); 224 | custom_repr.set_repr(r#""foo/bar""#.to_string()); 225 | assert_eq!(format!("{}", custom_repr), r#""foo/bar""#); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `kdl` is a "document-oriented" parser and API for the [KDL Document 2 | //! Language](https://kdl.dev), a node-based, human-friendly configuration and 3 | //! serialization format. 4 | //! 5 | //! Unlike serde-based implementations, this crate preserves formatting when 6 | //! editing, as well as when inserting or changing values with custom 7 | //! formatting. This is most useful when working with human-maintained KDL 8 | //! files. 9 | //! 10 | //! You can think of this crate as 11 | //! [`toml_edit`](https://crates.io/crates/toml_edit), but for KDL. 12 | //! 13 | //! This crate supports both KDL v2.0.0 and v1.0.0 (when using the non-default 14 | //! `v1` feature). It also supports converting documents between either format. 15 | //! 16 | //! There is also a `v1-fallback` feature that may be enabled in order to have 17 | //! the various `Kdl*::parse` methods try to parse their input as v2, and, if 18 | //! that fails, try again as v1. In either case, a dedicated `Kdl*::parse_v1` 19 | //! method is available for v1-exclusive parsing, as long as either `v1` or 20 | //! `v1-fallback` are enabled. 21 | //! 22 | //! ## Example 23 | //! 24 | //! ```rust 25 | //! use kdl::{KdlDocument, KdlValue}; 26 | //! 27 | //! let doc_str = r#" 28 | //! hello 1 2 3 29 | //! 30 | //! // Comment 31 | //! world prop=string-value { 32 | //! child 1 33 | //! child 2 34 | //! child #inf 35 | //! } 36 | //! "#; 37 | //! 38 | //! let doc: KdlDocument = doc_str.parse().expect("failed to parse KDL"); 39 | //! 40 | //! assert_eq!( 41 | //! doc.iter_args("hello").collect::>(), 42 | //! vec![&1.into(), &2.into(), &3.into()] 43 | //! ); 44 | //! 45 | //! assert_eq!( 46 | //! doc.get("world").map(|node| &node["prop"]), 47 | //! Some(&"string-value".into()) 48 | //! ); 49 | //! 50 | //! // Documents fully roundtrip: 51 | //! assert_eq!(doc.to_string(), doc_str); 52 | //! ``` 53 | //! 54 | //! ## Controlling Formatting 55 | //! 56 | //! By default, everything is created with default formatting. You can parse 57 | //! items manually to provide custom representations, comments, etc: 58 | //! 59 | //! ```rust 60 | //! let node_str = r#" 61 | //! // indented comment 62 | //! "formatted" 1 /* comment */ \ 63 | //! 2; 64 | //! "#; 65 | //! 66 | //! let mut doc = kdl::KdlDocument::new(); 67 | //! doc.nodes_mut().push(node_str.parse().unwrap()); 68 | //! 69 | //! assert_eq!(&doc.to_string(), node_str); 70 | //! ``` 71 | //! 72 | //! [`KdlDocument`], [`KdlNode`], [`KdlEntry`], and [`KdlIdentifier`] can all 73 | //! be parsed and managed this way. 74 | //! 75 | //! ## Error Reporting 76 | //! 77 | //! [`KdlError`] implements [`miette::Diagnostic`] and can be used to display 78 | //! detailed, pretty-printed diagnostic messages when using [`miette::Result`] 79 | //! and the `"fancy"` feature flag for `miette`: 80 | //! 81 | //! ```toml 82 | //! # Cargo.toml 83 | //! [dependencies] 84 | //! miette = { version = "x.y.z", features = ["fancy"] } 85 | //! ``` 86 | //! 87 | //! ```no_run 88 | //! fn main() -> miette::Result<()> { 89 | //! "foo 1.".parse::()?; 90 | //! Ok(()) 91 | //! } 92 | //! ``` 93 | //! 94 | //! This will display a message like: 95 | //! ```text 96 | //! Error: 97 | //! × Expected valid value. 98 | //! ╭──── 99 | //! 1 │ foo 1. 100 | //! · ─┬ 101 | //! · ╰── invalid float 102 | //! ╰──── 103 | //! help: Floating point numbers must be base 10, and have numbers after the decimal point. 104 | //! ``` 105 | //! 106 | //! ## Features 107 | //! 108 | //! * `span` (default) - Includes spans in the various document-related structs. 109 | //! * `v1` - Adds support for v1 parsing. This will pull in the entire previous 110 | //! version of `kdl-rs`, and so may be fairly heavy. 111 | //! * `v1-fallback` - Implies `v1`. Makes it so the various `*::parse()` and 112 | //! `FromStr` implementations try to parse their inputs as `v2`, and, if that 113 | //! fails, try again with `v1`. For `KdlDocument`, a heuristic will be applied 114 | //! if both `v1` and `v2` parsers fail, to pick which error(s) to return. For 115 | //! other types, only the `v2` parser's errors will be returned. 116 | //! 117 | //! ## Quirks 118 | //! 119 | //! ### Properties 120 | //! 121 | //! Multiple properties with the same name are allowed, and all duplicated 122 | //! **will be preserved**, meaning those documents will correctly round-trip. 123 | //! When using `node.get()`/`node["key"]` & company, the _last_ property with 124 | //! that name's value will be returned (as per spec). 125 | //! 126 | //! ### Numbers 127 | //! 128 | //! KDL itself does not specify a particular representation for numbers and 129 | //! accepts just about anything valid, no matter how large and how small. This 130 | //! means a few things: 131 | //! 132 | //! * Numbers without a decimal point are interpreted as [`i128`]. 133 | //! * Numbers with a decimal point are interpreted as [`f64`]. 134 | //! * The keywords `#inf`, `#-inf`, and `#nan` evaluate to [`f64::INFINITY`], 135 | //! [`f64::NEG_INFINITY`], and [`f64::NAN`]. 136 | //! * The original _representation/text_ of these numbers will be preserved, 137 | //! unless you [`KdlDocument::autoformat`] in which case the original 138 | //! representation will be thrown away and the actual value will be used when 139 | //! serializing. 140 | //! 141 | //! ## Minimum Supported Rust Version (MSRV) 142 | //! 143 | //! You must be at least `1.81` tall to get on this ride. 144 | //! 145 | //! ## License 146 | //! 147 | //! The code in this repository is covered by [the Apache-2.0 148 | //! License](./LICENSE). 149 | 150 | // TODO(@zkat): bring this back later. 151 | // ### Query Engine 152 | 153 | // `kdl` includes a query engine for 154 | // [KQL](https://github.com/kdl-org/kdl/blob/main/QUERY-SPEC.md), which lets you 155 | // pick out nodes from a document using a CSS Selectors-style syntax. 156 | 157 | // Queries can be done from either a [`KdlDocument`] or a [`KdlNode`], with 158 | // mostly the same semantics. 159 | 160 | // ```rust 161 | // use kdl::KdlDocument; 162 | 163 | // let doc = r#" 164 | // a { 165 | // b 1 166 | // c 2 167 | // d 3 { 168 | // e prop="hello" 169 | // } 170 | // } 171 | // "#.parse::().expect("failed to parse KDL"); 172 | 173 | // let results = doc.query("a > b").expect("failed to parse query"); 174 | // assert_eq!(results, Some(&doc.nodes()[0].children().unwrap().nodes()[0])); 175 | 176 | // let results = doc.query_get("e", "prop").expect("failed to parse query"); 177 | // assert_eq!(results, Some(&"hello".into())); 178 | 179 | // let results = doc.query_get_all("a > []", 0).expect("failed to parse query").collect::>(); 180 | // assert_eq!(results, vec![&1.into(), &2.into(), &3.into()]); 181 | // ``` 182 | 183 | #![deny(missing_debug_implementations, nonstandard_style)] 184 | #![warn(missing_docs, rust_2018_idioms, unreachable_pub)] 185 | #![cfg_attr(test, deny(warnings))] 186 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 187 | #![doc(html_favicon_url = "https://kdl.dev/favicon.ico")] 188 | #![doc(html_logo_url = "https://kdl.dev/logo.svg")] 189 | 190 | pub use document::*; 191 | pub use entry::*; 192 | pub use error::*; 193 | pub use fmt::*; 194 | pub use identifier::*; 195 | pub use node::*; 196 | // pub use query::*; 197 | pub use value::*; 198 | 199 | mod document; 200 | mod entry; 201 | mod error; 202 | mod fmt; 203 | mod identifier; 204 | mod node; 205 | // mod nom_compat; 206 | // mod query; 207 | // mod query_parser; 208 | // mod v1_parser; 209 | mod value; 210 | 211 | mod v2_parser; 212 | -------------------------------------------------------------------------------- /src/nom_compat.rs: -------------------------------------------------------------------------------- 1 | use nom::error::{ErrorKind, ParseError}; 2 | use nom::{Err, IResult, Parser}; 3 | 4 | pub(crate) fn many0(mut f: F) -> impl FnMut(I) -> IResult, E> 5 | where 6 | I: Clone + PartialEq, 7 | F: Parser, 8 | E: ParseError, 9 | { 10 | move |mut i: I| { 11 | let mut acc = Vec::with_capacity(4); 12 | loop { 13 | match f.parse(i.clone()) { 14 | Err(Err::Error(_)) => return Ok((i, acc)), 15 | Err(e) => return Err(e), 16 | Ok((i1, o)) => { 17 | if i1 == i { 18 | return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many0))); 19 | } 20 | 21 | i = i1; 22 | acc.push(o); 23 | } 24 | } 25 | } 26 | } 27 | } 28 | 29 | pub(crate) fn many1(mut f: F) -> impl FnMut(I) -> IResult, E> 30 | where 31 | I: Clone + PartialEq, 32 | F: Parser, 33 | E: ParseError, 34 | { 35 | move |mut i: I| match f.parse(i.clone()) { 36 | Err(Err::Error(err)) => Err(Err::Error(E::append(i, ErrorKind::Many1, err))), 37 | Err(e) => Err(e), 38 | Ok((i1, o)) => { 39 | let mut acc = Vec::with_capacity(4); 40 | acc.push(o); 41 | i = i1; 42 | 43 | loop { 44 | match f.parse(i.clone()) { 45 | Err(Err::Error(_)) => return Ok((i, acc)), 46 | Err(e) => return Err(e), 47 | Ok((i1, o)) => { 48 | if i1 == i { 49 | return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many1))); 50 | } 51 | 52 | i = i1; 53 | acc.push(o); 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | pub(crate) fn many_till( 62 | mut f: F, 63 | mut g: G, 64 | ) -> impl FnMut(I) -> IResult, P), E> 65 | where 66 | I: Clone + PartialEq, 67 | F: Parser, 68 | G: Parser, 69 | E: ParseError, 70 | { 71 | move |mut i: I| { 72 | let mut res = Vec::new(); 73 | loop { 74 | match g.parse(i.clone()) { 75 | Ok((i1, o)) => return Ok((i1, (res, o))), 76 | Err(Err::Error(_)) => { 77 | match f.parse(i.clone()) { 78 | Err(Err::Error(err)) => { 79 | return Err(Err::Error(E::append(i, ErrorKind::ManyTill, err))) 80 | } 81 | Err(e) => return Err(e), 82 | Ok((i1, o)) => { 83 | // loop trip must always consume (otherwise infinite loops) 84 | if i1 == i { 85 | return Err(Err::Error(E::from_error_kind( 86 | i1, 87 | ErrorKind::ManyTill, 88 | ))); 89 | } 90 | 91 | res.push(o); 92 | i = i1; 93 | } 94 | } 95 | } 96 | Err(e) => return Err(e), 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Full Document Test Cases 2 | 3 | The `input` folder contains test cases for KDL parsers. The `expected_kdl` 4 | folder contains files with the same name as those in `input` with the expected 5 | output after being run through the parser and printed out again. If there's no 6 | file in `expected_kdl` with a name corresponding to one in `input` it 7 | indicates that parsing for that case should fail. 8 | 9 | ## Translation Rules 10 | 11 | By necessity, the files in `expected_kdl` are not identical to their 12 | corresponding inputs. They are instead pretty-printed according to the 13 | following rules: 14 | 15 | * All comments removed 16 | * Extra empty lines removed except for a newline after the last node 17 | * All nodes should be reformatted without escaped newlines 18 | * Node fields should be `identifier ` 19 | * All values and all children must be in the same order as they were defined. 20 | * Properties must be in _alphabetical order_ and separated by a single space. 21 | * All strings must be represented as regular strings, with appropriate escapes 22 | for invalid bare characters. That means that raw strings must be converted 23 | to plain strings, and escaped. 24 | * Any literal newlines or other ascii escape characters in escaped strings 25 | replaced with their escape sequences. 26 | * All identifiers must be unquoted unless they _must_ be quoted. That means 27 | `"foo"` becomes `foo`, and `"foo bar"` stays that way. 28 | * Any duplicate properties must be removed, with only the rightmost one 29 | remaining. This also means duplicate properties must be allowed. 30 | * 4 space indents 31 | * All numbers must be converted to their simplest decimal representation. That 32 | means that hex, octal, and binary must all be converted to decimals. All 33 | floats must be represented using `E` notation, with a single digit left of 34 | the decimal point if the float is less than 1. While parsers are required to 35 | _consume_ different number syntaxes, they are under no obligation to 36 | represent numbers in any particular way. 37 | 38 | Data may be manipulated as you wish in order to output the expected KDL. This 39 | test suite verifies the ability to **parse**, not specific quirks about 40 | internal representations. 41 | 42 | ## What to do if a test fails for you 43 | 44 | This test suite was originally designed for a pre-1.0 version of the KDL 45 | specification. If you encounter a failure, it's likely that the test suite 46 | will need to be updated, rather than your parser itself. This test suite is 47 | NOT AUTHORITATIVE. If this test suite disagrees with the KDL spec in any way, 48 | the most desirable resolution is to send a PR to this repository to fix the 49 | test itself. Likewise, if you think a test succeeded but should not have, 50 | please send a PR. 51 | 52 | If you think the disagreement is due to a genuine error or oversight in the 53 | KDL specification, please open an issue explaining the matter and the change 54 | will be considered for the next version of the KDL spec. 55 | 56 | ## Credit 57 | 58 | This test suite was extracted from 59 | [`kdl4j`](https://github.com/hkolbeck/kdl4j), the original Java 60 | implementation of KDL, with huge thanks to 61 | [@hkolbeck](https://github.com/hkolbeck) for authoring them! 62 | -------------------------------------------------------------------------------- /tests/compliance.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::HashMap, 3 | fs, 4 | path::{Path, PathBuf}, 5 | }; 6 | 7 | use kdl::{KdlDocument, KdlError, KdlIdentifier, KdlValue}; 8 | use miette::{Diagnostic, IntoDiagnostic}; 9 | use thiserror::Error; 10 | 11 | #[derive(Debug, Error, Diagnostic)] 12 | #[error("Compliance test suite failed {} of {total_checks}.", diagnostics.len())] 13 | struct ComplianceSuiteFailure { 14 | total_checks: usize, 15 | #[related] 16 | diagnostics: Vec, 17 | } 18 | 19 | #[derive(Debug, Error, Diagnostic)] 20 | enum ComplianceDiagnostic { 21 | #[error("{}", PathBuf::from(.0.file_name().unwrap()).display())] 22 | #[diagnostic(code(kdl::compliance::parse_failure))] 23 | KdlError( 24 | PathBuf, 25 | #[source] 26 | #[diagnostic_source] 27 | KdlError, 28 | ), 29 | 30 | #[error("{}:\nExpected:\n{expected}\nActual:\n{actual}", PathBuf::from(file.file_name().unwrap()).display())] 31 | #[diagnostic(code(kdl::compliance::expectation_mismatch))] 32 | ExpectationMismatch { 33 | file: PathBuf, 34 | original: String, 35 | expected: String, 36 | actual: String, 37 | }, 38 | 39 | #[error(transparent)] 40 | #[diagnostic(code(kdl::compliance::io_error))] 41 | IoError(#[from] std::io::Error), 42 | } 43 | 44 | #[test] 45 | fn spec_compliance() -> miette::Result<()> { 46 | let input = PathBuf::from(env!("CARGO_MANIFEST_DIR")) 47 | .join("tests") 48 | .join("test_cases") 49 | .join("input"); 50 | let mut failures = Vec::new(); 51 | let mut count = 0usize; 52 | for test_name in fs::read_dir(input).into_diagnostic()? { 53 | let test_path = test_name.into_diagnostic()?.path(); 54 | let src = normalize_line_endings(fs::read_to_string(&test_path).into_diagnostic()?); 55 | let res = src.parse(); 56 | if let Err(e) = validate_res(res, &test_path, &src) { 57 | failures.push(e); 58 | } 59 | count += 1; 60 | } 61 | if failures.is_empty() { 62 | Ok(()) 63 | } else { 64 | let mut output = String::new(); 65 | for failure in &failures { 66 | output.push_str(format!("\n{failure}").as_str()); 67 | } 68 | Err(ComplianceSuiteFailure { 69 | total_checks: count, 70 | diagnostics: failures, 71 | } 72 | .into()) 73 | } 74 | } 75 | 76 | fn validate_res( 77 | res: Result, 78 | path: &Path, 79 | src: &str, 80 | ) -> Result<(), ComplianceDiagnostic> { 81 | let file_name = path.file_name().unwrap(); 82 | let expected_dir = path 83 | .parent() 84 | .unwrap() 85 | .parent() 86 | .unwrap() 87 | .join("expected_kdl"); 88 | let expected_path = expected_dir.join(file_name); 89 | let underscored = expected_dir.join(format!("_{}", PathBuf::from(file_name).display())); 90 | if expected_path.exists() { 91 | let doc = res.map_err(|e| ComplianceDiagnostic::KdlError(path.into(), e))?; 92 | let expected = normalize_line_endings(fs::read_to_string(&expected_path)?); 93 | let actual = stringify_to_expected(doc); 94 | if actual != expected { 95 | return Err(ComplianceDiagnostic::ExpectationMismatch { 96 | file: path.into(), 97 | original: src.into(), 98 | expected: expected.replace('\n', "\\n").replace(" ", "."), 99 | actual: actual.replace('\n', "\\n").replace(" ", "."), 100 | }); 101 | } 102 | } else if underscored.exists() { 103 | eprintln!( 104 | "skipped reserialization for {}", 105 | PathBuf::from(file_name).display() 106 | ); 107 | // } else { 108 | // res.map_err(|e| ComplianceDiagnostic::KdlError(path.into(), e))?; 109 | } 110 | Ok(()) 111 | } 112 | 113 | fn normalize_line_endings(src: String) -> String { 114 | src.replace("\r\n", "\n") 115 | } 116 | 117 | fn stringify_to_expected(mut doc: KdlDocument) -> String { 118 | doc.autoformat_no_comments(); 119 | normalize_strings(&mut doc); 120 | normalize_identifiers(&mut doc); 121 | dedupe_props(&mut doc); 122 | remove_empty_children(&mut doc); 123 | doc.to_string() 124 | } 125 | 126 | fn normalize_strings(doc: &mut KdlDocument) { 127 | for node in doc.nodes_mut() { 128 | for entry in node.entries_mut() { 129 | if let Some(value) = entry.value().as_string() { 130 | *entry.value_mut() = KdlValue::String(value.to_string()); 131 | } 132 | } 133 | if let Some(children) = node.children_mut() { 134 | normalize_strings(children); 135 | } 136 | } 137 | } 138 | 139 | fn normalize_identifiers(doc: &mut KdlDocument) { 140 | for node in doc.nodes_mut() { 141 | node.name_mut().clear_format(); 142 | for entry in node.entries_mut() { 143 | if entry.name().is_some() { 144 | if let Some(x) = entry.name_mut() { 145 | x.clear_format() 146 | } 147 | } 148 | } 149 | if let Some(children) = node.children_mut() { 150 | normalize_identifiers(children); 151 | } 152 | } 153 | } 154 | 155 | fn dedupe_props(doc: &mut KdlDocument) { 156 | for node in doc.nodes_mut() { 157 | let mut props = HashMap::>::new(); 158 | for (idx, entry) in node.entries_mut().iter_mut().enumerate() { 159 | if let Some(name) = entry.name() { 160 | if !props.contains_key(name) { 161 | props.insert(name.clone(), Vec::new()); 162 | } 163 | if let Some(indices) = props.get_mut(name) { 164 | indices.push(idx); 165 | } 166 | } 167 | } 168 | let new_entries = node 169 | .entries() 170 | .iter() 171 | .enumerate() 172 | .filter_map(|(idx, entry)| { 173 | if let Some(name) = entry.name() { 174 | if let Some(indices) = props.get(name) { 175 | if &idx == indices.last().unwrap() { 176 | return Some(entry.clone()); 177 | } else { 178 | return None; 179 | } 180 | } 181 | } 182 | Some(entry.clone()) 183 | }); 184 | *node.entries_mut() = new_entries.collect(); 185 | if let Some(children) = node.children_mut() { 186 | dedupe_props(children); 187 | } 188 | } 189 | } 190 | 191 | fn remove_empty_children(doc: &mut KdlDocument) { 192 | for node in doc.nodes_mut() { 193 | let maybe_children = node.children_mut(); 194 | if maybe_children.is_some() && maybe_children.as_ref().unwrap().nodes().is_empty() { 195 | *maybe_children = None; 196 | } 197 | if let Some(children) = maybe_children { 198 | remove_empty_children(children); 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /tests/disabled_tests/query_api.rs: -------------------------------------------------------------------------------- 1 | use kdl::{KdlDocument, KdlQuery}; 2 | use miette::Result; 3 | 4 | #[test] 5 | fn document_query_all() -> Result<()> { 6 | let doc = "foo\nbar\nbaz".parse::()?; 7 | let results = doc.query_all("bar")?; 8 | assert_eq!(results.count(), 1); 9 | let results = doc.query_all(String::from("bar"))?; 10 | assert_eq!(results.count(), 1); 11 | let results = doc.query_all(&String::from("bar"))?; 12 | assert_eq!(results.count(), 1); 13 | let results = doc.query_all("bar".parse::()?)?; 14 | assert_eq!(results.count(), 1); 15 | 16 | let results = doc.query_all("scope()")?; 17 | assert_eq!( 18 | results.count(), 19 | 0, 20 | "scope() on its own doesn't return anything if querying from a doc." 21 | ); 22 | 23 | Ok(()) 24 | } 25 | 26 | #[test] 27 | fn document_query() -> Result<()> { 28 | let doc = "foo\nbar\nbaz".parse::()?; 29 | 30 | assert!(doc.query("bar")?.is_some()); 31 | assert!(doc.query(String::from("bar"))?.is_some()); 32 | assert!(doc.query(&String::from("bar"))?.is_some()); 33 | assert!(doc.query("bar".parse::()?)?.is_some()); 34 | 35 | assert!(doc.query("scope()")?.is_none()); 36 | 37 | Ok(()) 38 | } 39 | 40 | #[test] 41 | fn document_query_get() -> Result<()> { 42 | let doc = "foo\nbar true\nbaz".parse::()?; 43 | 44 | assert_eq!(doc.query_get("bar", 0)?, Some(&true.into())); 45 | assert_eq!(doc.query_get(String::from("bar"), 0)?, Some(&true.into())); 46 | assert_eq!(doc.query_get(&String::from("bar"), 0)?, Some(&true.into())); 47 | assert_eq!( 48 | doc.query_get("bar".parse::()?, 0)?, 49 | Some(&true.into()) 50 | ); 51 | 52 | Ok(()) 53 | } 54 | 55 | #[test] 56 | fn document_query_get_all() -> Result<()> { 57 | let doc = "foo\nbar true\nbaz false".parse::()?; 58 | 59 | assert_eq!( 60 | doc.query_get_all("[]", 0)?.collect::>(), 61 | vec![&true.into(), &false.into()] 62 | ); 63 | assert_eq!(doc.query_get_all(String::from("[]"), 0)?.count(), 2); 64 | assert_eq!(doc.query_get_all(&String::from("[]"), 0)?.count(), 2); 65 | assert_eq!(doc.query_get_all("[]".parse::()?, 0)?.count(), 2); 66 | 67 | Ok(()) 68 | } 69 | 70 | #[test] 71 | fn node_query_all() -> Result<()> { 72 | let doc = r#" 73 | foo 74 | bar { 75 | a { 76 | b 77 | } 78 | } 79 | baz 80 | "# 81 | .parse::()?; 82 | let node = doc.query("bar")?.unwrap(); 83 | 84 | let results = node.query_all("b")?; 85 | assert_eq!(results.count(), 1); 86 | let results = node.query_all(String::from("b"))?; 87 | assert_eq!(results.count(), 1); 88 | let results = node.query_all(&String::from("b"))?; 89 | assert_eq!(results.count(), 1); 90 | let results = node.query_all("b".parse::()?)?; 91 | assert_eq!(results.count(), 1); 92 | 93 | let results = node.query_all("scope()")?.collect::>(); 94 | assert_eq!(results[0], node); 95 | 96 | let results = node.query_all("scope() > a".parse::()?)?; 97 | assert_eq!(results.count(), 1); 98 | 99 | let results = node.query_all("scope() > b".parse::()?)?; 100 | assert_eq!(results.count(), 0); 101 | 102 | Ok(()) 103 | } 104 | 105 | #[test] 106 | fn node_query() -> Result<()> { 107 | let doc = r#" 108 | foo 109 | bar { 110 | a { 111 | b 112 | } 113 | } 114 | baz 115 | "# 116 | .parse::()?; 117 | let node = doc.query("bar")?.unwrap(); 118 | 119 | assert!(node.query("b")?.is_some()); 120 | assert!(node.query(String::from("b"))?.is_some()); 121 | assert!(node.query(&String::from("b"))?.is_some()); 122 | assert!(node.query("b".parse::()?)?.is_some()); 123 | 124 | assert_eq!(node.query("scope()")?, Some(node)); 125 | assert!(node.query("scope() > a")?.is_some()); 126 | assert!(node.query("scope() > b")?.is_none()); 127 | 128 | Ok(()) 129 | } 130 | 131 | #[test] 132 | fn node_query_get() -> Result<()> { 133 | let doc = r#" 134 | foo 135 | bar 1 2 3 { 136 | a false { 137 | b true 138 | } 139 | } 140 | baz 141 | "# 142 | .parse::()?; 143 | let node = doc.query("bar")?.unwrap(); 144 | 145 | assert_eq!(node.query_get("b", 0)?, Some(&true.into())); 146 | assert_eq!(node.query_get(String::from("b"), 0)?, Some(&true.into())); 147 | assert_eq!(node.query_get(&String::from("b"), 0)?, Some(&true.into())); 148 | assert_eq!( 149 | node.query_get("b".parse::()?, 0)?, 150 | Some(&true.into()) 151 | ); 152 | 153 | assert_eq!(node.query_get("scope()", 0)?, Some(&1.into())); 154 | assert_eq!(node.query_get("scope() > a", 0)?, Some(&false.into())); 155 | assert!(node.query_get("scope() > b", "prop")?.is_none()); 156 | Ok(()) 157 | } 158 | 159 | #[test] 160 | fn node_query_get_all() -> Result<()> { 161 | let doc = r#" 162 | foo 163 | bar 1 2 3 { 164 | a false { 165 | b true 166 | } 167 | } 168 | baz 169 | "# 170 | .parse::()?; 171 | let node = doc.query("bar")?.unwrap(); 172 | 173 | assert_eq!( 174 | node.query_get_all("[]", 0)?.collect::>(), 175 | vec![&false.into(), &true.into()] 176 | ); 177 | assert_eq!(node.query_get_all(String::from("[]"), 0)?.count(), 2); 178 | assert_eq!(node.query_get_all(&String::from("[]"), 0)?.count(), 2); 179 | assert_eq!(node.query_get_all("[]".parse::()?, 0)?.count(), 2); 180 | 181 | Ok(()) 182 | } 183 | -------------------------------------------------------------------------------- /tests/disabled_tests/query_ops.rs: -------------------------------------------------------------------------------- 1 | use kdl::{KdlDocument, KdlNode}; 2 | use miette::Result; 3 | use pretty_assertions::assert_eq; 4 | 5 | #[test] 6 | fn scope_with_all_children() -> Result<()> { 7 | let doc: KdlDocument = r#" 8 | foo { 9 | bar 10 | baz 11 | } 12 | bar 13 | baz 14 | "# 15 | .parse()?; 16 | 17 | let results = doc.query_all("scope() > []")?.collect::>(); 18 | 19 | assert_eq!(&results, &doc.nodes().iter().collect::>()); 20 | Ok(()) 21 | } 22 | 23 | #[test] 24 | fn scope_child_by_name() -> Result<()> { 25 | let doc: KdlDocument = r#" 26 | foo { 27 | bar 28 | baz 29 | } 30 | bar { 31 | a 32 | b 33 | } 34 | baz 35 | "# 36 | .parse()?; 37 | 38 | let results = doc.query_all("scope() > bar")?.collect::>(); 39 | 40 | assert_eq!(results, vec![&doc.nodes()[1]]); 41 | 42 | // Scope from a specific node. 43 | let results = results[0] 44 | .query_all("scope() > a")? 45 | .collect::>(); 46 | 47 | assert_eq!( 48 | results, 49 | vec![&doc.nodes()[1].children().unwrap().nodes()[0]] 50 | ); 51 | 52 | Ok(()) 53 | } 54 | 55 | #[test] 56 | fn scope_descendants() -> Result<()> { 57 | let doc: KdlDocument = r#" 58 | foo { 59 | bar 60 | baz 61 | } 62 | bar 63 | baz 64 | "# 65 | .parse()?; 66 | 67 | let results = doc.query_all("scope() >> bar")?.collect::>(); 68 | 69 | assert_eq!( 70 | results, 71 | vec![ 72 | &doc.nodes()[0].children().unwrap().nodes()[0], 73 | &doc.nodes()[1] 74 | ] 75 | ); 76 | Ok(()) 77 | } 78 | 79 | #[test] 80 | fn scope_only_at_top() -> Result<()> { 81 | let doc: KdlDocument = r#" 82 | foo { 83 | bar 84 | } 85 | "# 86 | .parse()?; 87 | 88 | assert!( 89 | doc.query_all("foo >> scope()").is_err(), 90 | "scope() must be at the top level" 91 | ); 92 | 93 | Ok(()) 94 | } 95 | 96 | #[test] 97 | fn any_descendants() -> Result<()> { 98 | let doc: KdlDocument = r#" 99 | foo { 100 | bar 101 | baz 102 | } 103 | bar 104 | baz 105 | "# 106 | .parse()?; 107 | 108 | let results = doc.query_all("bar")?.collect::>(); 109 | 110 | assert_eq!( 111 | results, 112 | vec![ 113 | &doc.nodes()[0].children().unwrap().nodes()[0], 114 | &doc.nodes()[1] 115 | ] 116 | ); 117 | Ok(()) 118 | } 119 | 120 | #[test] 121 | fn node_descendants() -> Result<()> { 122 | let doc: KdlDocument = r#" 123 | foo { 124 | bar 125 | baz 126 | } 127 | bar 128 | baz { 129 | foo { 130 | bar { 131 | bar 132 | } 133 | } 134 | } 135 | "# 136 | .parse()?; 137 | 138 | let results = doc.query_all("foo >> bar")?.collect::>(); 139 | 140 | assert_eq!( 141 | results, 142 | vec![ 143 | &doc.nodes()[0].children().unwrap().nodes()[0], 144 | &doc.nodes()[2].children().unwrap().nodes()[0] 145 | .children() 146 | .unwrap() 147 | .nodes()[0], 148 | &doc.nodes()[2].children().unwrap().nodes()[0] 149 | .children() 150 | .unwrap() 151 | .nodes()[0] 152 | .children() 153 | .unwrap() 154 | .nodes()[0] 155 | ] 156 | ); 157 | Ok(()) 158 | } 159 | 160 | #[test] 161 | fn node_children() -> Result<()> { 162 | let doc: KdlDocument = r#" 163 | foo { 164 | bar 165 | baz 166 | } 167 | bar 168 | baz { 169 | foo { 170 | bar { 171 | bar 172 | } 173 | } 174 | } 175 | "# 176 | .parse()?; 177 | 178 | let results = doc.query_all("foo > bar")?.collect::>(); 179 | 180 | assert_eq!( 181 | results, 182 | vec![ 183 | &doc.nodes()[0].children().unwrap().nodes()[0], 184 | &doc.nodes()[2].children().unwrap().nodes()[0] 185 | .children() 186 | .unwrap() 187 | .nodes()[0] 188 | ] 189 | ); 190 | Ok(()) 191 | } 192 | 193 | #[test] 194 | fn node_neighbor() -> Result<()> { 195 | let doc: KdlDocument = r#" 196 | foo { 197 | bar 198 | baz 199 | } 200 | bar 201 | baz 202 | "# 203 | .parse()?; 204 | 205 | let results = doc.query_all("foo + bar")?.collect::>(); 206 | 207 | assert_eq!(results, vec![&doc.nodes()[1]]); 208 | 209 | let results = doc.query_all("foo + bar + baz")?.collect::>(); 210 | 211 | assert_eq!(results, vec![&doc.nodes()[2]]); 212 | 213 | Ok(()) 214 | } 215 | 216 | #[test] 217 | fn node_sibling() -> Result<()> { 218 | let doc: KdlDocument = r#" 219 | foo { 220 | bar 221 | baz 222 | } 223 | bar 224 | baz 225 | quux 226 | other 227 | "# 228 | .parse()?; 229 | 230 | let results = doc.query_all("foo ++ bar")?.collect::>(); 231 | 232 | assert_eq!(results, vec![&doc.nodes()[1]]); 233 | 234 | let results = doc.query_all("foo ++ baz")?.collect::>(); 235 | 236 | assert_eq!(results, vec![&doc.nodes()[2]]); 237 | 238 | let results = doc 239 | .query_all("foo ++ bar ++ other")? 240 | .collect::>(); 241 | 242 | assert_eq!(results, vec![&doc.nodes()[4]]); 243 | 244 | Ok(()) 245 | } 246 | 247 | #[test] 248 | fn multiple_selectors() -> Result<()> { 249 | let doc: KdlDocument = r#" 250 | foo { 251 | bar 252 | baz 253 | } 254 | bar 255 | baz { 256 | foo { 257 | bar { 258 | bar 259 | } 260 | } 261 | } 262 | "# 263 | .parse()?; 264 | 265 | let results = doc.query_all("foo, baz")?.collect::>(); 266 | 267 | assert_eq!( 268 | results, 269 | vec![ 270 | &doc.nodes()[0], 271 | &doc.nodes()[0].children().unwrap().nodes()[1], 272 | &doc.nodes()[2], 273 | &doc.nodes()[2].children().unwrap().nodes()[0] 274 | ], 275 | "First match all the `foo`s, then all the `baz`s." 276 | ); 277 | 278 | Ok(()) 279 | } 280 | 281 | #[test] 282 | fn all_combined() -> Result<()> { 283 | let doc: KdlDocument = r#" 284 | foo { 285 | bar { 286 | baz { 287 | foo { 288 | bar { 289 | bar 290 | } 291 | } 292 | bar 293 | baz 294 | quux 295 | other 296 | } 297 | } 298 | } 299 | bar 300 | baz 301 | "# 302 | .parse()?; 303 | 304 | let results = doc 305 | .query_all("foo >> baz > foo + bar ++ other")? 306 | .collect::>(); 307 | 308 | assert_eq!( 309 | results, 310 | vec![ 311 | &doc.nodes()[0].children().unwrap().nodes()[0] 312 | .children() 313 | .unwrap() 314 | .nodes()[0] 315 | .children() 316 | .unwrap() 317 | .nodes()[4] 318 | ] 319 | ); 320 | Ok(()) 321 | } 322 | -------------------------------------------------------------------------------- /tests/disabled_tests/query_syntax.rs: -------------------------------------------------------------------------------- 1 | use kdl::KdlDocument; 2 | use miette::Result; 3 | 4 | #[test] 5 | fn syntax_errors() -> Result<()> { 6 | macro_rules! assert_syntax_errors { 7 | ($(($input:expr, $msg:expr, ($offset:expr, $len:expr))),*) => { 8 | $( 9 | let err = "node".parse::() 10 | .unwrap() 11 | .query_all($input) 12 | .expect_err("query parse should've failed."); 13 | assert_eq!(err.to_string(), $msg, "unexpected error message"); 14 | assert_eq!(err.span.offset(), $offset, "unexpected span offset"); 15 | assert_eq!(err.span.len(), $len, "unexpected span length"); 16 | )* 17 | } 18 | } 19 | 20 | assert_syntax_errors! { 21 | ("", "Expected a valid node matcher.", (0, 0)), 22 | (" scope(", "Expected a valid scope accessor.", (1, 6)), 23 | ("(", "Expected closing ')' for type annotation.", (0, 1)), 24 | (")", "Expected a valid node matcher.", (0, 0)), 25 | ("[", "Expected a closing ']' for this attribute matcher.", (0, 1)), 26 | ("]", "Expected a valid node matcher.", (0, 0)), 27 | ("a b", "Expected a valid KQL query.", (2, 0)), 28 | ("a\nb", "Expected a valid KQL query.", (2, 0)), 29 | (",", "Expected a valid node matcher.", (0, 0)), 30 | ("[] > scope( )", "Expected scope() to be the first item in this selector.", (5, 8)), 31 | ("()(type)", "Expected only one type annotation per selector.", (2, 6)), 32 | ("(type)()", "Expected only one type annotation per selector.", (6, 2)), 33 | ("name(type)", "Expected type annotation to not be used after a node name.", (4, 6)), 34 | ("[]name", "Expected node name to come before attribute matcher(s).", (2, 4)), 35 | ("[]()", "Expected type annotation to come before attribute matcher(s).", (2, 2)), 36 | ("[type(blah)]", "Expected a closing ')' for this 'type()' accessor.", (1, 5)), 37 | ("[scope()]", "Expected 'scope()' to be the first item only at the top level of the query selector.", (1, 7)), 38 | ("[scope ( )]", "Expected 'scope()' to be the first item only at the top level of the query selector.", (1, 9)), 39 | ("[other()]", "Expected a valid attribute accessor.", (1, 7)), 40 | ("[arg()1]", "Expected a closing ']' for this attribute matcher.", (0, 6)), 41 | ("[arg() 1]", "Expected a closing ']' for this attribute matcher.", (0, 7)), 42 | ("[arg()=identifier]", "Expected a valid operator argument.", (7, 0)), 43 | // // Only string values are allowed here. 44 | ("[arg()*=1]", "Expected a string as an operator value.", (8, 1)), 45 | ("[arg()^=1]", "Expected a string as an operator value.", (8, 1)), 46 | ("[arg()$=1]", "Expected a string as an operator value.", (8, 1)), 47 | ("[arg()*=null]", "Expected a string as an operator value.", (8, 4)), 48 | ("[arg()^=null]", "Expected a string as an operator value.", (8, 4)), 49 | ("[arg()$=null]", "Expected a string as an operator value.", (8, 4)), 50 | ("[arg()*=true]", "Expected a string as an operator value.", (8, 4)), 51 | ("[arg()^=true]", "Expected a string as an operator value.", (8, 4)), 52 | ("[arg()$=true]", "Expected a string as an operator value.", (8, 4)) 53 | } 54 | 55 | Ok(()) 56 | } 57 | -------------------------------------------------------------------------------- /tests/formatting.rs: -------------------------------------------------------------------------------- 1 | use kdl::{KdlDocument, KdlNode}; 2 | 3 | #[test] 4 | fn build_and_format() { 5 | let mut c = KdlNode::new("c"); 6 | c.ensure_children(); 7 | let mut b = KdlNode::new("b"); 8 | b.ensure_children().nodes_mut().push(c); 9 | let mut a = KdlNode::new("a"); 10 | a.ensure_children().nodes_mut().push(b); 11 | 12 | let mut doc = KdlDocument::new(); 13 | doc.nodes_mut().push(a); 14 | doc.autoformat(); 15 | let fmt = doc.to_string(); 16 | assert_eq!( 17 | fmt, 18 | r#"a { 19 | b { 20 | c { 21 | } 22 | } 23 | } 24 | "# 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/all_escapes.kdl: -------------------------------------------------------------------------------- 1 | node "\"\\\b\f\n\r\t " 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/all_node_fields.kdl: -------------------------------------------------------------------------------- 1 | node arg prop=val { 2 | inner_node 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_and_prop_same_name.kdl: -------------------------------------------------------------------------------- 1 | node arg arg=val 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_bare.kdl: -------------------------------------------------------------------------------- 1 | node a 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_false_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_float_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)2.5 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_hex_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)16 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_null_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#null 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_raw_string_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)str 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_string_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)str 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_true_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/arg_zero_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/asterisk_in_block_comment.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/bare_emoji.kdl: -------------------------------------------------------------------------------- 1 | 😁 happy! 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/bare_ident_dot.kdl: -------------------------------------------------------------------------------- 1 | node . 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/bare_ident_sign.kdl: -------------------------------------------------------------------------------- 1 | node + 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/bare_ident_sign_dot.kdl: -------------------------------------------------------------------------------- 1 | node +. 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/binary.kdl: -------------------------------------------------------------------------------- 1 | node 2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/binary_trailing_underscore.kdl: -------------------------------------------------------------------------------- 1 | node 2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/binary_underscore.kdl: -------------------------------------------------------------------------------- 1 | node 2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/blank_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node ("")10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/blank_node_type.kdl: -------------------------------------------------------------------------------- 1 | ("")node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/blank_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=("")#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/block_comment.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/block_comment_after_node.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/block_comment_before_node.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/block_comment_before_node_no_space.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/block_comment_newline.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/bom_initial.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/boolean_arg.kdl: -------------------------------------------------------------------------------- 1 | node #false #true 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/boolean_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop1=#true prop2=#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/chevrons_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | foo123foo weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/comma_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | foo123,bar weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/comment_after_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/comment_after_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/comment_after_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/comment_and_newline.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/comment_in_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/comment_in_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/comment_in_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/commented_arg.kdl: -------------------------------------------------------------------------------- 1 | node arg2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/commented_child.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/commented_line.kdl: -------------------------------------------------------------------------------- 1 | node_2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/commented_node.kdl: -------------------------------------------------------------------------------- 1 | node_2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/commented_prop.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/crlf_between_nodes.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/dash_dash.kdl: -------------------------------------------------------------------------------- 1 | node -- 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/emoji.kdl: -------------------------------------------------------------------------------- 1 | node 😀 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/empty.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/empty_child.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/empty_child_different_lines.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/empty_child_same_line.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/empty_child_whitespace.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/empty_line_comment.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/empty_quoted_node_id.kdl: -------------------------------------------------------------------------------- 1 | "" arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/empty_quoted_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node ""=empty 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/empty_string_arg.kdl: -------------------------------------------------------------------------------- 1 | node "" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/eof_after_escape.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/esc_multiple_newlines.kdl: -------------------------------------------------------------------------------- 1 | node "12" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/esc_newline_in_string.kdl: -------------------------------------------------------------------------------- 1 | node "hello\nworld" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/esc_unicode_in_string.kdl: -------------------------------------------------------------------------------- 1 | node "hello\nworld" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escaped_whitespace.kdl: -------------------------------------------------------------------------------- 1 | node "Hello\n\tWorld" "Hello\n\tWorld" "Hello\n\tWorld" "Hello\n\tWorld" "Hello\n\tWorld" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline_after_semicolon.kdl: -------------------------------------------------------------------------------- 1 | node 2 | node 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline_alone.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline_empty_line.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline_end_of_node.kdl: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline_in_child_block.kdl: -------------------------------------------------------------------------------- 1 | parent { 2 | child 3 | child 4 | } 5 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline_line_comment.kdl: -------------------------------------------------------------------------------- 1 | node arg arg2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline_node.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/escline_slashdash.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/false_prefix_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | false_id 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/false_prefix_in_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node false_id=1 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/floating_point_keywords.kdl: -------------------------------------------------------------------------------- 1 | floats #inf #-inf #nan 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/hex_int.kdl: -------------------------------------------------------------------------------- 1 | node 188900966474565 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/hex_int_underscores.kdl: -------------------------------------------------------------------------------- 1 | node 737894400291 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/hex_leading_zero.kdl: -------------------------------------------------------------------------------- 1 | node 1 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/initial_slashdash.kdl: -------------------------------------------------------------------------------- 1 | another-node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/int_multiple_underscore.kdl: -------------------------------------------------------------------------------- 1 | node 1234 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/just_block_comment.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/just_child.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | inner_node 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/just_newline.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/just_node_id.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/just_space.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/leading_newline.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/leading_zero_binary.kdl: -------------------------------------------------------------------------------- 1 | node 1 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/leading_zero_int.kdl: -------------------------------------------------------------------------------- 1 | node 11 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/leading_zero_oct.kdl: -------------------------------------------------------------------------------- 1 | node 1 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_comment.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_nodes.kdl: -------------------------------------------------------------------------------- 1 | node arg1 arg2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_raw_string.kdl: -------------------------------------------------------------------------------- 1 | node "hey\neveryone\nhow goes?" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_raw_string_containing_quotes.kdl: -------------------------------------------------------------------------------- 1 | node "\"\"\"triple-quote\"\"\"\n##\"too few quotes\"##\n#\"\"\"too few #\"\"\"#" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_raw_string_indented.kdl: -------------------------------------------------------------------------------- 1 | node " hey\n everyone\n how goes?" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_string.kdl: -------------------------------------------------------------------------------- 1 | node "hey\neveryone\nhow goes?" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_string_containing_quotes.kdl: -------------------------------------------------------------------------------- 1 | node "this string contains \"quotes\", twice\"\"" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_string_double_backslash.kdl: -------------------------------------------------------------------------------- 1 | node "a\\ b\na\\b" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_string_escape_delimiter.kdl: -------------------------------------------------------------------------------- 1 | node "\"\"\"" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_string_escape_in_closing_line.kdl: -------------------------------------------------------------------------------- 1 | node "foo bar\nbaz" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_string_escape_in_closing_line_shallow.kdl: -------------------------------------------------------------------------------- 1 | node " foo bar\n baz" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_string_escape_newline_at_end.kdl: -------------------------------------------------------------------------------- 1 | node " a" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_string_indented.kdl: -------------------------------------------------------------------------------- 1 | node " hey\n everyone\n how goes?" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/multiline_string_whitespace_only.kdl: -------------------------------------------------------------------------------- 1 | node "" "" "" "\n\n " "\n" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/negative_exponent.kdl: -------------------------------------------------------------------------------- 1 | node 1e-10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/negative_float.kdl: -------------------------------------------------------------------------------- 1 | node -1.0 key=-10.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/negative_int.kdl: -------------------------------------------------------------------------------- 1 | node -10 prop=-15 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/nested_block_comment.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/nested_children.kdl: -------------------------------------------------------------------------------- 1 | node1 { 2 | node2 { 3 | node 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/nested_comments.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/nested_multiline_block_comment.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/newline_between_nodes.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/newlines_in_block_comment.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/no_decimal_exponent.kdl: -------------------------------------------------------------------------------- 1 | node 10000000000.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/node_false.kdl: -------------------------------------------------------------------------------- 1 | node #false 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/node_true.kdl: -------------------------------------------------------------------------------- 1 | node #true 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/null_arg.kdl: -------------------------------------------------------------------------------- 1 | node #null 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/null_prefix_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | null_id 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/null_prefix_in_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node null_id=1 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/null_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop=#null 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/numeric_arg.kdl: -------------------------------------------------------------------------------- 1 | node 15.7 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/numeric_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop=10.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/octal.kdl: -------------------------------------------------------------------------------- 1 | node 16434824 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/only_cr.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/only_line_comment.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/only_line_comment_crlf.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/only_line_comment_newline.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/optional_child_semicolon.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | foo 3 | bar 4 | baz 5 | } 6 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/parse_all_arg_types.kdl: -------------------------------------------------------------------------------- 1 | node 1 1.0 10000000000.0 1e-10 1 7 2 arg arg "arg\\" #true #false #null 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/positive_exponent.kdl: -------------------------------------------------------------------------------- 1 | node 10000000000.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/positive_int.kdl: -------------------------------------------------------------------------------- 1 | node 10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/preserve_duplicate_nodes.kdl: -------------------------------------------------------------------------------- 1 | node 2 | node 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/preserve_node_order.kdl: -------------------------------------------------------------------------------- 1 | node2 2 | node5 3 | node1 4 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_false_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_float_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)25000000000.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_hex_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)16 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_identifier_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)str 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_null_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#null 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_raw_string_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)str 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_string_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)str 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_true_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/prop_zero_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/question_mark_before_number.kdl: -------------------------------------------------------------------------------- 1 | node ?15 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/quoted_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node ("type/")10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/quoted_node_name.kdl: -------------------------------------------------------------------------------- 1 | "0node" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/quoted_node_type.kdl: -------------------------------------------------------------------------------- 1 | ("type/")node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/quoted_numeric.kdl: -------------------------------------------------------------------------------- 1 | node prop="10.0" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/quoted_prop_name.kdl: -------------------------------------------------------------------------------- 1 | node "0prop"=val 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/quoted_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=("type/")#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/r_node.kdl: -------------------------------------------------------------------------------- 1 | r arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_node_name.kdl: -------------------------------------------------------------------------------- 1 | "\\node" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_string_arg.kdl: -------------------------------------------------------------------------------- 1 | node_1 "\"arg\\n\"and #stuff" 2 | node_2 "#\"arg\\n\"#and #stuff" 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_string_backslash.kdl: -------------------------------------------------------------------------------- 1 | node "\\n" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_string_hash_no_esc.kdl: -------------------------------------------------------------------------------- 1 | node "#" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_string_just_backslash.kdl: -------------------------------------------------------------------------------- 1 | node "\\" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_string_multiple_hash.kdl: -------------------------------------------------------------------------------- 1 | node "\"#\"##" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_string_newline.kdl: -------------------------------------------------------------------------------- 1 | node "hello\nworld" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_string_prop.kdl: -------------------------------------------------------------------------------- 1 | node_1 prop="\"arg#\"\\n" 2 | node_2 prop="#\"arg#\"#\\n" 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/raw_string_quote.kdl: -------------------------------------------------------------------------------- 1 | node "a\"b" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/repeated_arg.kdl: -------------------------------------------------------------------------------- 1 | node arg arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/repeated_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop=11 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/same_name_nodes.kdl: -------------------------------------------------------------------------------- 1 | node 2 | node 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/sci_notation_large.kdl: -------------------------------------------------------------------------------- 1 | node prop=#inf 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/sci_notation_small.kdl: -------------------------------------------------------------------------------- 1 | node prop=0.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/semicolon_after_child.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | childnode 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/semicolon_in_child.kdl: -------------------------------------------------------------------------------- 1 | node1 { 2 | node2 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/semicolon_separated.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/semicolon_separated_nodes.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/semicolon_terminated.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/single_arg.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/single_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop=val 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_arg_after_newline_esc.kdl: -------------------------------------------------------------------------------- 1 | node arg2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_arg_before_newline_esc.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_child.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_empty_child.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_escline_before_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node arg2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_escline_before_children.kdl: -------------------------------------------------------------------------------- 1 | node arg1 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_escline_before_node.kdl: -------------------------------------------------------------------------------- 1 | node2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_false_node.kdl: -------------------------------------------------------------------------------- 1 | node foo bar 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_full_node.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_in_slashdash.kdl: -------------------------------------------------------------------------------- 1 | node2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_multi_line_comment_entry.kdl: -------------------------------------------------------------------------------- 1 | node 1 3 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_multi_line_comment_inline.kdl: -------------------------------------------------------------------------------- 1 | node 1 3 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_multiple_child_blocks.kdl: -------------------------------------------------------------------------------- 1 | node foo { 2 | three 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_negative_number.kdl: -------------------------------------------------------------------------------- 1 | node 2.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_newline_before_children.kdl: -------------------------------------------------------------------------------- 1 | node 1 2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_newline_before_entry.kdl: -------------------------------------------------------------------------------- 1 | node 1 3 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_newline_before_node.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_node_in_child.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_node_with_child.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_only_node.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_only_node_with_space.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_prop.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_raw_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_repeated_prop.kdl: -------------------------------------------------------------------------------- 1 | node arg=correct 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_single_line_comment_entry.kdl: -------------------------------------------------------------------------------- 1 | node 1 3 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/slashdash_single_line_comment_node.kdl: -------------------------------------------------------------------------------- 1 | node2 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/space_after_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/space_after_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/space_after_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/space_around_prop_marker.kdl: -------------------------------------------------------------------------------- 1 | node foo=bar 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/space_in_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/space_in_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/space_in_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/string_arg.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/string_escaped_literal_whitespace.kdl: -------------------------------------------------------------------------------- 1 | node "Hello World Stuff" 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/string_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop=val 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/tab_space.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/trailing_crlf.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/trailing_underscore_hex.kdl: -------------------------------------------------------------------------------- 1 | node 1194684 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/trailing_underscore_octal.kdl: -------------------------------------------------------------------------------- 1 | node 83 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/true_prefix_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | true_id 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/true_prefix_in_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node true_id=1 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/two_nodes.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/underscore_before_number.kdl: -------------------------------------------------------------------------------- 1 | node _15 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/underscore_in_exponent.kdl: -------------------------------------------------------------------------------- 1 | node 1e-100 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/underscore_in_float.kdl: -------------------------------------------------------------------------------- 1 | node 11.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/underscore_in_fraction.kdl: -------------------------------------------------------------------------------- 1 | node 1.02 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/underscore_in_int.kdl: -------------------------------------------------------------------------------- 1 | node 10 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/underscore_in_octal.kdl: -------------------------------------------------------------------------------- 1 | node 342391 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/unicode_silly.kdl: -------------------------------------------------------------------------------- 1 | ノード お名前=ฅ^•ﻌ•^ฅ 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/unusual_bare_id_chars_in_quoted_id.kdl: -------------------------------------------------------------------------------- 1 | foo123~!@$%^&*.:'|?+<>,`-_ weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/unusual_chars_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | foo123~!@$%^&*.:'|?+<>,`-_ weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/vertical_tab_whitespace.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | node2 arg2 3 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/zero_float.kdl: -------------------------------------------------------------------------------- 1 | node 0.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/expected_kdl/zero_int.kdl: -------------------------------------------------------------------------------- 1 | node 0 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/all_escapes.kdl: -------------------------------------------------------------------------------- 1 | node "\"\\\b\f\n\r\t\s" 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/all_node_fields.kdl: -------------------------------------------------------------------------------- 1 | node arg prop=val { 2 | inner_node 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_and_prop_same_name.kdl: -------------------------------------------------------------------------------- 1 | node arg arg=val 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_bare.kdl: -------------------------------------------------------------------------------- 1 | node a 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_false_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_float_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)2.5 -------------------------------------------------------------------------------- /tests/test_cases/input/arg_hex_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)0x10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_null_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#null 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_raw_string_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#"str"# 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_string_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)"str" 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_true_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/arg_zero_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)0 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/asterisk_in_block_comment.kdl: -------------------------------------------------------------------------------- 1 | node /* * */ -------------------------------------------------------------------------------- /tests/test_cases/input/bare_emoji.kdl: -------------------------------------------------------------------------------- 1 | 😁 happy! 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/bare_ident_dot.kdl: -------------------------------------------------------------------------------- 1 | node . -------------------------------------------------------------------------------- /tests/test_cases/input/bare_ident_numeric_dot_fail.kdl: -------------------------------------------------------------------------------- 1 | node .0n -------------------------------------------------------------------------------- /tests/test_cases/input/bare_ident_numeric_fail.kdl: -------------------------------------------------------------------------------- 1 | node 0n -------------------------------------------------------------------------------- /tests/test_cases/input/bare_ident_numeric_sign_fail.kdl: -------------------------------------------------------------------------------- 1 | node +0n -------------------------------------------------------------------------------- /tests/test_cases/input/bare_ident_sign.kdl: -------------------------------------------------------------------------------- 1 | node + -------------------------------------------------------------------------------- /tests/test_cases/input/bare_ident_sign_dot.kdl: -------------------------------------------------------------------------------- 1 | node +. -------------------------------------------------------------------------------- /tests/test_cases/input/binary.kdl: -------------------------------------------------------------------------------- 1 | node 0b10 -------------------------------------------------------------------------------- /tests/test_cases/input/binary_trailing_underscore.kdl: -------------------------------------------------------------------------------- 1 | node 0b10_ -------------------------------------------------------------------------------- /tests/test_cases/input/binary_underscore.kdl: -------------------------------------------------------------------------------- 1 | node 0b1_0 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/blank_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node ("")10 -------------------------------------------------------------------------------- /tests/test_cases/input/blank_node_type.kdl: -------------------------------------------------------------------------------- 1 | ("")node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/blank_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=("")#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/block_comment.kdl: -------------------------------------------------------------------------------- 1 | node /* comment */ arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/block_comment_after_node.kdl: -------------------------------------------------------------------------------- 1 | node /* hey */ arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/block_comment_before_node.kdl: -------------------------------------------------------------------------------- 1 | /* hey */ node -------------------------------------------------------------------------------- /tests/test_cases/input/block_comment_before_node_no_space.kdl: -------------------------------------------------------------------------------- 1 | /* hey*/node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/block_comment_newline.kdl: -------------------------------------------------------------------------------- 1 | /* hey */ 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/bom_initial.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/bom_later_fail.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/boolean_arg.kdl: -------------------------------------------------------------------------------- 1 | node #false #true 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/boolean_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop1=#true prop2=#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/brackets_in_bare_id_fail.kdl: -------------------------------------------------------------------------------- 1 | foo123{bar}foo weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/chevrons_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | foo123foo weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/comma_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | foo123,bar weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/comment_after_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)/*hey*/10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/comment_after_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)/*hey*/node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/comment_after_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)/*hey*/10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/comment_and_newline.kdl: -------------------------------------------------------------------------------- 1 | node1 // 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/comment_in_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type/*hey*/)10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/comment_in_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type/*hey*/)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/comment_in_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type/*hey*/)10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/commented_arg.kdl: -------------------------------------------------------------------------------- 1 | node /- arg1 arg2 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/commented_child.kdl: -------------------------------------------------------------------------------- 1 | node arg /- { 2 | inner_node 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/commented_line.kdl: -------------------------------------------------------------------------------- 1 | // node_1 2 | node_2 -------------------------------------------------------------------------------- /tests/test_cases/input/commented_node.kdl: -------------------------------------------------------------------------------- 1 | /- node_1 2 | node_2 3 | /- node_3 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/commented_prop.kdl: -------------------------------------------------------------------------------- 1 | node /- prop=val arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/crlf_between_nodes.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/dash_dash.kdl: -------------------------------------------------------------------------------- 1 | node -- 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/dot_but_no_fraction_before_exponent_fail.kdl: -------------------------------------------------------------------------------- 1 | node 1.e7 -------------------------------------------------------------------------------- /tests/test_cases/input/dot_but_no_fraction_fail.kdl: -------------------------------------------------------------------------------- 1 | node 1. -------------------------------------------------------------------------------- /tests/test_cases/input/dot_in_exponent_fail.kdl: -------------------------------------------------------------------------------- 1 | node 1.0.0 -------------------------------------------------------------------------------- /tests/test_cases/input/dot_zero_fail.kdl: -------------------------------------------------------------------------------- 1 | node .0 -------------------------------------------------------------------------------- /tests/test_cases/input/emoji.kdl: -------------------------------------------------------------------------------- 1 | node 😀 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/empty.kdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdl-org/kdl-rs/439aa63bfc595432e6dc6b0fdd708c364628ab18/tests/test_cases/input/empty.kdl -------------------------------------------------------------------------------- /tests/test_cases/input/empty_arg_type_fail.kdl: -------------------------------------------------------------------------------- 1 | node ()10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/empty_child.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | } -------------------------------------------------------------------------------- /tests/test_cases/input/empty_child_different_lines.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | } -------------------------------------------------------------------------------- /tests/test_cases/input/empty_child_same_line.kdl: -------------------------------------------------------------------------------- 1 | node {} -------------------------------------------------------------------------------- /tests/test_cases/input/empty_child_whitespace.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | 3 | } -------------------------------------------------------------------------------- /tests/test_cases/input/empty_line_comment.kdl: -------------------------------------------------------------------------------- 1 | // 2 | node -------------------------------------------------------------------------------- /tests/test_cases/input/empty_node_type_fail.kdl: -------------------------------------------------------------------------------- 1 | ()node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/empty_prop_type_fail.kdl: -------------------------------------------------------------------------------- 1 | node key=()#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/empty_quoted_node_id.kdl: -------------------------------------------------------------------------------- 1 | "" arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/empty_quoted_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node ""=empty 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/empty_string_arg.kdl: -------------------------------------------------------------------------------- 1 | node "" 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/eof_after_escape.kdl: -------------------------------------------------------------------------------- 1 | node \ -------------------------------------------------------------------------------- /tests/test_cases/input/err_backslash_in_bare_id_fail.kdl: -------------------------------------------------------------------------------- 1 | foo123\bar weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/esc_multiple_newlines.kdl: -------------------------------------------------------------------------------- 1 | node "1\ 2 | 3 | 4 | 2" 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/esc_newline_in_string.kdl: -------------------------------------------------------------------------------- 1 | node "hello\nworld" -------------------------------------------------------------------------------- /tests/test_cases/input/esc_unicode_in_string.kdl: -------------------------------------------------------------------------------- 1 | node "hello\u{0a}world" 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/escaped_whitespace.kdl: -------------------------------------------------------------------------------- 1 | // All of these strings are the same 2 | node \ 3 | "Hello\n\tWorld" \ 4 | """ 5 | Hello 6 | World 7 | """ \ 8 | "Hello\n\ \tWorld" \ 9 | "Hello\n\ 10 | \tWorld" \ 11 | "Hello\n\t\ 12 | World" 13 | 14 | // Note that this file deliberately mixes space and newline indentation for 15 | // test purposes 16 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline.kdl: -------------------------------------------------------------------------------- 1 | node \ 2 | arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline_after_semicolon.kdl: -------------------------------------------------------------------------------- 1 | node; \ 2 | node 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline_alone.kdl: -------------------------------------------------------------------------------- 1 | \ 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline_empty_line.kdl: -------------------------------------------------------------------------------- 1 | \ 2 | 3 | node 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline_end_of_node.kdl: -------------------------------------------------------------------------------- 1 | a \ 2 | 3 | b 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline_in_child_block.kdl: -------------------------------------------------------------------------------- 1 | parent { 2 | child 3 | \ // comment 4 | child 5 | } 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline_line_comment.kdl: -------------------------------------------------------------------------------- 1 | node \ // comment 2 | arg \// comment 3 | arg2 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline_node.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | \ 3 | node2 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline_node_type.kdl: -------------------------------------------------------------------------------- 1 | \ 2 | (type)node 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/escline_slashdash.kdl: -------------------------------------------------------------------------------- 1 | node 2 | \ 3 | /- 4 | node 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/false_prefix_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | false_id 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/false_prefix_in_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node false_id=1 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/false_prop_key_fail.kdl: -------------------------------------------------------------------------------- 1 | node false=1 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/floating_point_keyword_identifier_strings_fail.kdl: -------------------------------------------------------------------------------- 1 | floats inf -inf nan 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/floating_point_keywords.kdl: -------------------------------------------------------------------------------- 1 | floats #inf #-inf #nan 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/hash_in_id_fail.kdl: -------------------------------------------------------------------------------- 1 | foo#bar weee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/hex.kdl: -------------------------------------------------------------------------------- 1 | node 0xabcdef1234567890 -------------------------------------------------------------------------------- /tests/test_cases/input/hex_int.kdl: -------------------------------------------------------------------------------- 1 | node 0xABCDEF012345 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/hex_int_underscores.kdl: -------------------------------------------------------------------------------- 1 | node 0xABC_def_0123 -------------------------------------------------------------------------------- /tests/test_cases/input/hex_leading_zero.kdl: -------------------------------------------------------------------------------- 1 | node 0x01 -------------------------------------------------------------------------------- /tests/test_cases/input/illegal_char_in_binary_fail.kdl: -------------------------------------------------------------------------------- 1 | node 0bx01 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/illegal_char_in_hex_fail.kdl: -------------------------------------------------------------------------------- 1 | node 0x10g10 -------------------------------------------------------------------------------- /tests/test_cases/input/illegal_char_in_octal_fail.kdl: -------------------------------------------------------------------------------- 1 | node 0o45678 -------------------------------------------------------------------------------- /tests/test_cases/input/initial_slashdash.kdl: -------------------------------------------------------------------------------- 1 | /-node here 2 | another-node 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/int_multiple_underscore.kdl: -------------------------------------------------------------------------------- 1 | node 1_2_3_4 -------------------------------------------------------------------------------- /tests/test_cases/input/just_block_comment.kdl: -------------------------------------------------------------------------------- 1 | /* hey */ -------------------------------------------------------------------------------- /tests/test_cases/input/just_child.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | inner_node 3 | } -------------------------------------------------------------------------------- /tests/test_cases/input/just_newline.kdl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/just_node_id.kdl: -------------------------------------------------------------------------------- 1 | node -------------------------------------------------------------------------------- /tests/test_cases/input/just_space.kdl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test_cases/input/just_space_in_arg_type_fail.kdl: -------------------------------------------------------------------------------- 1 | node ( )false 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/just_space_in_node_type_fail.kdl: -------------------------------------------------------------------------------- 1 | ( )node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/just_space_in_prop_type_fail.kdl: -------------------------------------------------------------------------------- 1 | node key=( )0x10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/just_type_no_arg_fail.kdl: -------------------------------------------------------------------------------- 1 | node (type) 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/just_type_no_node_id_fail.kdl: -------------------------------------------------------------------------------- 1 | (type) 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/just_type_no_prop_fail.kdl: -------------------------------------------------------------------------------- 1 | node key=(type) 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/leading_newline.kdl: -------------------------------------------------------------------------------- 1 | 2 | node -------------------------------------------------------------------------------- /tests/test_cases/input/leading_zero_binary.kdl: -------------------------------------------------------------------------------- 1 | node 0b01 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/leading_zero_int.kdl: -------------------------------------------------------------------------------- 1 | node 011 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/leading_zero_oct.kdl: -------------------------------------------------------------------------------- 1 | node 0o01 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/legacy_raw_string_fail.kdl: -------------------------------------------------------------------------------- 1 | node r"foo" 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/legacy_raw_string_hash_fail.kdl: -------------------------------------------------------------------------------- 1 | node r#"foo"# 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_comment.kdl: -------------------------------------------------------------------------------- 1 | node /* 2 | some 3 | comments 4 | */ arg 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_nodes.kdl: -------------------------------------------------------------------------------- 1 | node \ 2 | arg1 \// comment 3 | arg2 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_raw_string.kdl: -------------------------------------------------------------------------------- 1 | node #""" 2 | hey 3 | everyone 4 | how goes? 5 | """# 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_raw_string_containing_quotes.kdl: -------------------------------------------------------------------------------- 1 | node ##""" 2 | """triple-quote""" 3 | ##"too few quotes"## 4 | #"""too few #"""# 5 | """## 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_raw_string_indented.kdl: -------------------------------------------------------------------------------- 1 | node #""" 2 | hey 3 | everyone 4 | how goes? 5 | """# 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_raw_string_non_matching_prefix_character_error_fail.kdl: -------------------------------------------------------------------------------- 1 | node #""" 2 | hey 3 | everyone 4 | how goes? 5 | """# 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_raw_string_non_matching_prefix_count_error_fail.kdl: -------------------------------------------------------------------------------- 1 | node #""" 2 | hey 3 | everyone 4 | how goes? 5 | """# 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_raw_string_single_line_err_fail.kdl: -------------------------------------------------------------------------------- 1 | node #"""one line"""# -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_raw_string_single_quote_err_fail.kdl: -------------------------------------------------------------------------------- 1 | node #" 2 | hey 3 | everyone 4 | how goes? 5 | "# 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | hey 3 | everyone 4 | how goes? 5 | """ 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_containing_quotes.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | this string contains "quotes", twice"" 3 | """ 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_double_backslash.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | a\\ b 3 | a\\\ b 4 | """ 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_escape_delimiter.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | \""" 3 | """ 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_escape_in_closing_line.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | foo \ 3 | bar 4 | baz 5 | \ """ 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_escape_in_closing_line_shallow.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | foo \ 3 | bar 4 | baz 5 | \ """ 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_escape_newline_at_end.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | a 3 | \ 4 | """ 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_escape_newline_at_end_fail.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | a 3 | \ 4 | """ 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_final_whitespace_escape_fail.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | foo 3 | bar\ 4 | """ -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_indented.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | hey 3 | everyone 4 | how goes? 5 | """ 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_non_literal_prefix_fail.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | \s escaped prefix 3 | literal prefix 4 | """ 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_non_matching_prefix_character_error_fail.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | hey 3 | everyone 4 | how goes? 5 | """ 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_non_matching_prefix_count_error_fail.kdl: -------------------------------------------------------------------------------- 1 | node """ 2 | hey 3 | everyone 4 | how goes? 5 | """ 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_single_line_err_fail.kdl: -------------------------------------------------------------------------------- 1 | node """one line""" -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_single_quote_err_fail.kdl: -------------------------------------------------------------------------------- 1 | node " 2 | hey 3 | everyone 4 | how goes? 5 | " 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiline_string_whitespace_only.kdl: -------------------------------------------------------------------------------- 1 | // This file deliberately contains unusual whitespace 2 | // The first two strings are empty 3 | node """ 4 |   """ """ 5 |    \ 6 |    7 |    """ """ 8 |    9 |  """\ 10 | \ // The next two strings contains only whitespace 11 | """ 12 |    13 | 14 |    \s 15 |    """ #""" 16 |      17 | 18 | """# 19 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiple_dots_in_float_before_exponent_fail.kdl: -------------------------------------------------------------------------------- 1 | node 1.0.0e7 -------------------------------------------------------------------------------- /tests/test_cases/input/multiple_dots_in_float_fail.kdl: -------------------------------------------------------------------------------- 1 | node 1.0.0 -------------------------------------------------------------------------------- /tests/test_cases/input/multiple_es_in_float_fail.kdl: -------------------------------------------------------------------------------- 1 | node 1.0E10e10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/multiple_x_in_hex_fail.kdl: -------------------------------------------------------------------------------- 1 | node 0xx10 -------------------------------------------------------------------------------- /tests/test_cases/input/negative_exponent.kdl: -------------------------------------------------------------------------------- 1 | node 1.0e-10 -------------------------------------------------------------------------------- /tests/test_cases/input/negative_float.kdl: -------------------------------------------------------------------------------- 1 | node -1.0 key=-10.0 -------------------------------------------------------------------------------- /tests/test_cases/input/negative_int.kdl: -------------------------------------------------------------------------------- 1 | node -10 prop=-15 -------------------------------------------------------------------------------- /tests/test_cases/input/nested_block_comment.kdl: -------------------------------------------------------------------------------- 1 | node /* hi /* there */ everyone */ arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/nested_children.kdl: -------------------------------------------------------------------------------- 1 | node1 { 2 | node2 { 3 | node 4 | } 5 | } -------------------------------------------------------------------------------- /tests/test_cases/input/nested_comments.kdl: -------------------------------------------------------------------------------- 1 | node /*/* nested */*/ arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/nested_multiline_block_comment.kdl: -------------------------------------------------------------------------------- 1 | node /* 2 | hey /* 3 | how's 4 | */ 5 | it going 6 | */ arg 7 | -------------------------------------------------------------------------------- /tests/test_cases/input/newline_between_nodes.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/newlines_in_block_comment.kdl: -------------------------------------------------------------------------------- 1 | node /* hey so 2 | I was thinking 3 | about newts */ arg 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/no_decimal_exponent.kdl: -------------------------------------------------------------------------------- 1 | node 1e10 -------------------------------------------------------------------------------- /tests/test_cases/input/no_digits_in_hex_fail.kdl: -------------------------------------------------------------------------------- 1 | node 0x -------------------------------------------------------------------------------- /tests/test_cases/input/no_integer_digit_fail.kdl: -------------------------------------------------------------------------------- 1 | node .1 -------------------------------------------------------------------------------- /tests/test_cases/input/no_solidus_escape_fail.kdl: -------------------------------------------------------------------------------- 1 | node "\/" 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/node_false.kdl: -------------------------------------------------------------------------------- 1 | node #false 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/node_true.kdl: -------------------------------------------------------------------------------- 1 | node #true 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)node -------------------------------------------------------------------------------- /tests/test_cases/input/null_arg.kdl: -------------------------------------------------------------------------------- 1 | node #null 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/null_prefix_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | null_id 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/null_prefix_in_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node null_id=1 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/null_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop=#null 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/null_prop_key_fail.kdl: -------------------------------------------------------------------------------- 1 | node null=1 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/numeric_arg.kdl: -------------------------------------------------------------------------------- 1 | node 15.7 -------------------------------------------------------------------------------- /tests/test_cases/input/numeric_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop=10.0 -------------------------------------------------------------------------------- /tests/test_cases/input/octal.kdl: -------------------------------------------------------------------------------- 1 | node 0o76543210 -------------------------------------------------------------------------------- /tests/test_cases/input/only_cr.kdl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test_cases/input/only_line_comment.kdl: -------------------------------------------------------------------------------- 1 | // hi -------------------------------------------------------------------------------- /tests/test_cases/input/only_line_comment_crlf.kdl: -------------------------------------------------------------------------------- 1 | // comment 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/only_line_comment_newline.kdl: -------------------------------------------------------------------------------- 1 | // hiiii 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/optional_child_semicolon.kdl: -------------------------------------------------------------------------------- 1 | node {foo;bar;baz} 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/parens_in_bare_id_fail.kdl: -------------------------------------------------------------------------------- 1 | foo123(bar)foo weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/parse_all_arg_types.kdl: -------------------------------------------------------------------------------- 1 | node 1 1.0 1.0e10 1.0e-10 0x01 0o07 0b10 arg "arg" #"arg\"# #true #false #null 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/positive_exponent.kdl: -------------------------------------------------------------------------------- 1 | node 1.0e+10 -------------------------------------------------------------------------------- /tests/test_cases/input/positive_int.kdl: -------------------------------------------------------------------------------- 1 | node +10 -------------------------------------------------------------------------------- /tests/test_cases/input/preserve_duplicate_nodes.kdl: -------------------------------------------------------------------------------- 1 | node 2 | node 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/preserve_node_order.kdl: -------------------------------------------------------------------------------- 1 | node2 2 | node5 3 | node1 -------------------------------------------------------------------------------- /tests/test_cases/input/prop_false_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/prop_float_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)2.5E10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/prop_hex_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)0x10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/prop_identifier_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)str 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/prop_null_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#null 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/prop_raw_string_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#"str"# 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/prop_string_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)"str" 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/prop_true_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/prop_zero_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)0 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/question_mark_before_number.kdl: -------------------------------------------------------------------------------- 1 | node ?15 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/quote_in_bare_id_fail.kdl: -------------------------------------------------------------------------------- 1 | foo123"bar weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/quoted_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node ("type/")10 -------------------------------------------------------------------------------- /tests/test_cases/input/quoted_node_name.kdl: -------------------------------------------------------------------------------- 1 | "0node" -------------------------------------------------------------------------------- /tests/test_cases/input/quoted_node_type.kdl: -------------------------------------------------------------------------------- 1 | ("type/")node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/quoted_numeric.kdl: -------------------------------------------------------------------------------- 1 | node prop="10.0" -------------------------------------------------------------------------------- /tests/test_cases/input/quoted_prop_name.kdl: -------------------------------------------------------------------------------- 1 | node "0prop"=val 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/quoted_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=("type/")#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/r_node.kdl: -------------------------------------------------------------------------------- 1 | r "arg" 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_node_name.kdl: -------------------------------------------------------------------------------- 1 | #"\node"# 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type)node -------------------------------------------------------------------------------- /tests/test_cases/input/raw_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type)#true 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_string_arg.kdl: -------------------------------------------------------------------------------- 1 | node_1 #""arg\n"and #stuff"# 2 | node_2 ##"#"arg\n"#and #stuff"## 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_string_backslash.kdl: -------------------------------------------------------------------------------- 1 | node #"\n"# 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_string_hash_no_esc.kdl: -------------------------------------------------------------------------------- 1 | node #"#"# 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_string_just_backslash.kdl: -------------------------------------------------------------------------------- 1 | node #"\"# 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_string_just_quote_fail.kdl: -------------------------------------------------------------------------------- 1 | // This fails because `"""` MUST be followed by a newline. 2 | node #"""# 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_string_multiple_hash.kdl: -------------------------------------------------------------------------------- 1 | node ###""#"##"### 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_string_newline.kdl: -------------------------------------------------------------------------------- 1 | node #""" 2 | hello 3 | world 4 | """# 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_string_prop.kdl: -------------------------------------------------------------------------------- 1 | node_1 prop=#""arg#"\n"# 2 | node_2 prop=##"#"arg#"#\n"## 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/raw_string_quote.kdl: -------------------------------------------------------------------------------- 1 | node #"a"b"# 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/repeated_arg.kdl: -------------------------------------------------------------------------------- 1 | node arg arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/repeated_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop=10 prop=11 -------------------------------------------------------------------------------- /tests/test_cases/input/same_name_nodes.kdl: -------------------------------------------------------------------------------- 1 | node 2 | node 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/sci_notation_large.kdl: -------------------------------------------------------------------------------- 1 | node prop=1.23E+1000 -------------------------------------------------------------------------------- /tests/test_cases/input/sci_notation_small.kdl: -------------------------------------------------------------------------------- 1 | node prop=1.23E-1000 -------------------------------------------------------------------------------- /tests/test_cases/input/semicolon_after_child.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | childnode 3 | }; 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/semicolon_in_child.kdl: -------------------------------------------------------------------------------- 1 | node1 { 2 | node2; 3 | } -------------------------------------------------------------------------------- /tests/test_cases/input/semicolon_separated.kdl: -------------------------------------------------------------------------------- 1 | node1;node2 -------------------------------------------------------------------------------- /tests/test_cases/input/semicolon_separated_nodes.kdl: -------------------------------------------------------------------------------- 1 | node1; node2; -------------------------------------------------------------------------------- /tests/test_cases/input/semicolon_terminated.kdl: -------------------------------------------------------------------------------- 1 | node1; -------------------------------------------------------------------------------- /tests/test_cases/input/single_arg.kdl: -------------------------------------------------------------------------------- 1 | node arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/single_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop=val 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slash_in_bare_id_fail.kdl: -------------------------------------------------------------------------------- 1 | foo123/bar weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_after_arg_type_fail.kdl: -------------------------------------------------------------------------------- 1 | node (ty)/-arg1 arg2 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_after_node_type_fail.kdl: -------------------------------------------------------------------------------- 1 | (ty)/-node 2 | other-node 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_after_prop_key_fail.kdl: -------------------------------------------------------------------------------- 1 | node key /- = value 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_after_prop_val_type_fail.kdl: -------------------------------------------------------------------------------- 1 | node key=(ty)/-val other-arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_after_type_fail.kdl: -------------------------------------------------------------------------------- 1 | node (type) /- arg1 arg2 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_arg_after_newline_esc.kdl: -------------------------------------------------------------------------------- 1 | node \ 2 | /- arg arg2 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_arg_before_newline_esc.kdl: -------------------------------------------------------------------------------- 1 | node /- \ 2 | arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_before_children_end_fail.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | child1 3 | /- 4 | } 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_before_eof_fail.kdl: -------------------------------------------------------------------------------- 1 | node foo /- 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_before_prop_value_fail.kdl: -------------------------------------------------------------------------------- 1 | node key = /-val etc 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_before_semicolon_fail.kdl: -------------------------------------------------------------------------------- 1 | node foo /-; 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_between_child_blocks_fail.kdl: -------------------------------------------------------------------------------- 1 | node { one } /- { two } { three } 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_child.kdl: -------------------------------------------------------------------------------- 1 | node /- { 2 | node2 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_child_block_before_entry_err_fail.kdl: -------------------------------------------------------------------------------- 1 | node /-{ 2 | child 3 | } foo { 4 | bar 5 | } 6 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_empty_child.kdl: -------------------------------------------------------------------------------- 1 | node /- { 2 | } 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_escline_before_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node /-\ 2 | (ty)arg1 arg2 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_escline_before_children.kdl: -------------------------------------------------------------------------------- 1 | node arg1 /-\ 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_escline_before_node.kdl: -------------------------------------------------------------------------------- 1 | /-\ 2 | node1 3 | node2 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_false_node.kdl: -------------------------------------------------------------------------------- 1 | node foo /- 2 | not-a-node bar 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_full_node.kdl: -------------------------------------------------------------------------------- 1 | /- node 1.0 "a" b=""" 2 | b 3 | """ 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_in_slashdash.kdl: -------------------------------------------------------------------------------- 1 | /- node1 /- 1.0 2 | node2 -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_inside_arg_type_fail.kdl: -------------------------------------------------------------------------------- 1 | node (/-bad)nope 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_inside_node_type_fail.kdl: -------------------------------------------------------------------------------- 1 | (/-ty)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_multi_line_comment_entry.kdl: -------------------------------------------------------------------------------- 1 | node 1 /- /* 2 | multi 3 | line 4 | comment 5 | here 6 | */ 2 3 7 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_multi_line_comment_inline.kdl: -------------------------------------------------------------------------------- 1 | node 1 /-/*two*/2 3 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_multiple_child_blocks.kdl: -------------------------------------------------------------------------------- 1 | node foo /-{ 2 | one 3 | } \ 4 | /-{ 5 | two 6 | } { 7 | three 8 | } /-{ 9 | four 10 | } 11 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_negative_number.kdl: -------------------------------------------------------------------------------- 1 | node /--1.0 2.0 -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_newline_before_children.kdl: -------------------------------------------------------------------------------- 1 | node 1 2 /- 2 | { 3 | child 4 | } 5 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_newline_before_entry.kdl: -------------------------------------------------------------------------------- 1 | node 1 /- 2 | 2 3 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_newline_before_node.kdl: -------------------------------------------------------------------------------- 1 | /- 2 | node 1 2 3 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_node_in_child.kdl: -------------------------------------------------------------------------------- 1 | node1 { 2 | /- node2 3 | } -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_node_with_child.kdl: -------------------------------------------------------------------------------- 1 | /- node { 2 | node2 3 | } -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_only_node.kdl: -------------------------------------------------------------------------------- 1 | /-node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_only_node_with_space.kdl: -------------------------------------------------------------------------------- 1 | /- node -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_prop.kdl: -------------------------------------------------------------------------------- 1 | node /- key=value arg 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_raw_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node /- key=value 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_repeated_prop.kdl: -------------------------------------------------------------------------------- 1 | node arg=correct /- arg=wrong 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_single_line_comment_entry.kdl: -------------------------------------------------------------------------------- 1 | node 1 /- // stuff 2 | 2 3 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/slashdash_single_line_comment_node.kdl: -------------------------------------------------------------------------------- 1 | /- // this is a comment 2 | node1 3 | node2 4 | -------------------------------------------------------------------------------- /tests/test_cases/input/space_after_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type) 10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/space_after_node_type.kdl: -------------------------------------------------------------------------------- 1 | (type) node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/space_after_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type) #false 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/space_around_prop_marker.kdl: -------------------------------------------------------------------------------- 1 | node foo = bar 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/space_in_arg_type.kdl: -------------------------------------------------------------------------------- 1 | node (type )#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/space_in_node_type.kdl: -------------------------------------------------------------------------------- 1 | ( type)node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/space_in_prop_type.kdl: -------------------------------------------------------------------------------- 1 | node key=(type )#false 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/square_bracket_in_bare_id_fail.kdl: -------------------------------------------------------------------------------- 1 | foo123[bar]foo weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/string_arg.kdl: -------------------------------------------------------------------------------- 1 | node "arg" -------------------------------------------------------------------------------- /tests/test_cases/input/string_escaped_literal_whitespace.kdl: -------------------------------------------------------------------------------- 1 | node "Hello \ 2 | World \ Stuff" 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/string_prop.kdl: -------------------------------------------------------------------------------- 1 | node prop="val" -------------------------------------------------------------------------------- /tests/test_cases/input/tab_space.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/trailing_crlf.kdl: -------------------------------------------------------------------------------- 1 | node 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/trailing_underscore_hex.kdl: -------------------------------------------------------------------------------- 1 | node 0x123abc_ -------------------------------------------------------------------------------- /tests/test_cases/input/trailing_underscore_octal.kdl: -------------------------------------------------------------------------------- 1 | node 0o123_ 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/true_prefix_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | true_id 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/true_prefix_in_prop_key.kdl: -------------------------------------------------------------------------------- 1 | node true_id=1 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/true_prop_key_fail.kdl: -------------------------------------------------------------------------------- 1 | node true=1 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/two_nodes.kdl: -------------------------------------------------------------------------------- 1 | node1 2 | node2 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/type_before_prop_key_fail.kdl: -------------------------------------------------------------------------------- 1 | node (type)key=10 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/unbalanced_raw_hashes_fail.kdl: -------------------------------------------------------------------------------- 1 | node ##"foo"# 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/underscore_at_start_of_fraction_fail.kdl: -------------------------------------------------------------------------------- 1 | node 1._7 -------------------------------------------------------------------------------- /tests/test_cases/input/underscore_at_start_of_hex_fail.kdl: -------------------------------------------------------------------------------- 1 | node 0x_10 -------------------------------------------------------------------------------- /tests/test_cases/input/underscore_before_number.kdl: -------------------------------------------------------------------------------- 1 | node _15 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/underscore_in_exponent.kdl: -------------------------------------------------------------------------------- 1 | node 1.0e-10_0 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/underscore_in_float.kdl: -------------------------------------------------------------------------------- 1 | node 1_1.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/underscore_in_fraction.kdl: -------------------------------------------------------------------------------- 1 | node 1.0_2 -------------------------------------------------------------------------------- /tests/test_cases/input/underscore_in_int.kdl: -------------------------------------------------------------------------------- 1 | node 1_0 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/underscore_in_octal.kdl: -------------------------------------------------------------------------------- 1 | node 0o012_3456_7 -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_delete_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x007F (Delete) 2 | node1 arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_fsi_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x2068 2 | node1 ⁨arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_lre_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x202A 2 | node1 ‪arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_lri_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x2066 2 | node1⁦arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_lrm_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x200E 2 | node ‎arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_lro_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x202D 2 | node ‭arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_pdf_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x202C 2 | node ‬arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_pdi_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x2069 2 | node ⁩arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_rle_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x202B 2 | node1 ‫arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_rli_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x2067 2 | node1 ⁧arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_rlm_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x200F 2 | node ‏arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_rlo_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x202E 2 | node ‮arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_silly.kdl: -------------------------------------------------------------------------------- 1 | ノード お名前=ฅ^•ﻌ•^ฅ 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/unicode_under_0x20_fail.kdl: -------------------------------------------------------------------------------- 1 | // 0x0019 2 | node1 arg 3 | -------------------------------------------------------------------------------- /tests/test_cases/input/unterminated_empty_node_fail.kdl: -------------------------------------------------------------------------------- 1 | node { 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/unusual_bare_id_chars_in_quoted_id.kdl: -------------------------------------------------------------------------------- 1 | "foo123~!@$%^&*.:'|?+<>,`-_" weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/unusual_chars_in_bare_id.kdl: -------------------------------------------------------------------------------- 1 | foo123~!@$%^&*.:'|?+<>,`-_ weeee 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/vertical_tab_whitespace.kdl: -------------------------------------------------------------------------------- 1 | node arg node2 arg2 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/zero_float.kdl: -------------------------------------------------------------------------------- 1 | node 0.0 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/zero_int.kdl: -------------------------------------------------------------------------------- 1 | node 0 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/zero_space_before_first_arg_fail.kdl: -------------------------------------------------------------------------------- 1 | node"string" 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/zero_space_before_prop_fail.kdl: -------------------------------------------------------------------------------- 1 | node foo="value"bar=5 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/zero_space_before_second_arg_fail.kdl: -------------------------------------------------------------------------------- 1 | node "string"1 2 | -------------------------------------------------------------------------------- /tests/test_cases/input/zero_space_before_slashdash_arg_fail.kdl: -------------------------------------------------------------------------------- 1 | node "string"/-1 2 | -------------------------------------------------------------------------------- /tools/kdl-lsp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kdl-lsp" 3 | version = "6.3.3" 4 | edition = "2021" 5 | description = "LSP Server for the KDL Document Language" 6 | authors = ["Kat Marchán ", "KDL Community"] 7 | license = "Apache-2.0" 8 | readme = "README.md" 9 | homepage = "https://kdl.dev" 10 | repository = "https://github.com/kdl-org/kdl-rs" 11 | keywords = ["kdl", "document", "config", "lsp", "language-server"] 12 | rust-version = "1.81" 13 | 14 | [dependencies] 15 | miette.workspace = true 16 | kdl = { version = "6.3.3", path = "../../", features = ["span", "v1-fallback"] } 17 | tower-lsp = "0.20.0" 18 | dashmap = "6.1.0" 19 | ropey = "1.6.1" 20 | tokio = { version = "1.43.0", features = ["full"] } 21 | tracing = "0.1.41" 22 | tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } 23 | -------------------------------------------------------------------------------- /tools/kdl-lsp/README.md: -------------------------------------------------------------------------------- 1 | # `kdl-lsp` 2 | 3 | This is an LSP server for KDL. 4 | 5 | Currently, it only supports diagnostics, which it generates using 6 | [`kdl-rs`](https://github.com/kdl-org/kdl-rs). 7 | 8 | It will eventually support richer diagnostics, completions, and KDL Schema. -------------------------------------------------------------------------------- /tools/kdl-lsp/src/main.rs: -------------------------------------------------------------------------------- 1 | use dashmap::DashMap; 2 | use kdl::{KdlDocument, KdlError}; 3 | use miette::Diagnostic as _; 4 | use ropey::Rope; 5 | use tower_lsp::jsonrpc::Result; 6 | use tower_lsp::lsp_types::*; 7 | use tower_lsp::{Client, LanguageServer, LspService, Server}; 8 | use tracing_subscriber::prelude::*; 9 | use tracing_subscriber::EnvFilter; 10 | 11 | #[derive(Debug)] 12 | struct Backend { 13 | client: Client, 14 | document_map: DashMap, 15 | } 16 | 17 | impl Backend { 18 | async fn on_change(&self, uri: Url, text: &str) { 19 | let rope = ropey::Rope::from_str(text); 20 | self.document_map.insert(uri.to_string(), rope.clone()); 21 | } 22 | } 23 | 24 | #[tower_lsp::async_trait] 25 | impl LanguageServer for Backend { 26 | async fn initialize(&self, _: InitializeParams) -> Result { 27 | Ok(InitializeResult { 28 | capabilities: ServerCapabilities { 29 | text_document_sync: Some(TextDocumentSyncCapability::Options( 30 | TextDocumentSyncOptions { 31 | open_close: Some(true), 32 | change: Some(TextDocumentSyncKind::FULL), 33 | save: Some(TextDocumentSyncSaveOptions::SaveOptions(SaveOptions { 34 | include_text: Some(true), 35 | })), 36 | ..Default::default() 37 | }, 38 | )), 39 | workspace: Some(WorkspaceServerCapabilities { 40 | workspace_folders: Some(WorkspaceFoldersServerCapabilities { 41 | supported: Some(true), 42 | change_notifications: Some(OneOf::Left(true)), 43 | }), 44 | file_operations: None, 45 | }), 46 | diagnostic_provider: Some(DiagnosticServerCapabilities::RegistrationOptions( 47 | DiagnosticRegistrationOptions { 48 | text_document_registration_options: TextDocumentRegistrationOptions { 49 | document_selector: Some(vec![DocumentFilter { 50 | language: Some("kdl".into()), 51 | scheme: Some("file".into()), 52 | pattern: None, 53 | }]), 54 | }, 55 | ..Default::default() 56 | }, 57 | )), 58 | // hover_provider: Some(HoverProviderCapability::Simple(true)), 59 | // completion_provider: Some(Default::default()), 60 | ..Default::default() 61 | }, 62 | ..Default::default() 63 | }) 64 | } 65 | 66 | async fn initialized(&self, _: InitializedParams) { 67 | self.client 68 | .log_message(MessageType::INFO, "server initialized!") 69 | .await; 70 | } 71 | 72 | async fn shutdown(&self) -> Result<()> { 73 | self.client 74 | .log_message(MessageType::INFO, "server shutting down") 75 | .await; 76 | Ok(()) 77 | } 78 | 79 | async fn did_open(&self, params: DidOpenTextDocumentParams) { 80 | self.on_change(params.text_document.uri, ¶ms.text_document.text) 81 | .await; 82 | } 83 | 84 | async fn did_change(&self, params: DidChangeTextDocumentParams) { 85 | self.on_change(params.text_document.uri, ¶ms.content_changes[0].text) 86 | .await; 87 | } 88 | 89 | async fn did_save(&self, params: DidSaveTextDocumentParams) { 90 | if let Some(text) = params.text.as_ref() { 91 | self.on_change(params.text_document.uri, text).await; 92 | } 93 | } 94 | 95 | async fn did_close(&self, params: DidCloseTextDocumentParams) { 96 | self.document_map 97 | .remove(¶ms.text_document.uri.to_string()); 98 | } 99 | 100 | async fn diagnostic( 101 | &self, 102 | params: DocumentDiagnosticParams, 103 | ) -> Result { 104 | tracing::debug!("diagnostic req"); 105 | if let Some(doc) = self.document_map.get(¶ms.text_document.uri.to_string()) { 106 | let res: std::result::Result = doc.to_string().parse(); 107 | if let Err(kdl_err) = res { 108 | let diags = kdl_err 109 | .diagnostics 110 | .into_iter() 111 | .map(|diag| { 112 | Diagnostic::new( 113 | Range::new( 114 | char_to_position(diag.span.offset(), &doc), 115 | char_to_position(diag.span.offset() + diag.span.len(), &doc), 116 | ), 117 | diag.severity().map(to_lsp_sev), 118 | diag.code().map(|c| NumberOrString::String(c.to_string())), 119 | None, 120 | diag.to_string(), 121 | None, 122 | None, 123 | ) 124 | }) 125 | .collect(); 126 | return Ok(DocumentDiagnosticReportResult::Report( 127 | DocumentDiagnosticReport::Full(RelatedFullDocumentDiagnosticReport { 128 | related_documents: None, 129 | full_document_diagnostic_report: FullDocumentDiagnosticReport { 130 | result_id: None, 131 | items: diags, 132 | }, 133 | }), 134 | )); 135 | } 136 | } 137 | Ok(DocumentDiagnosticReportResult::Report( 138 | DocumentDiagnosticReport::Full(RelatedFullDocumentDiagnosticReport::default()), 139 | )) 140 | } 141 | 142 | // TODO(@zkat): autocomplete #-keywords 143 | // TODO(@zkat): autocomplete schema stuff 144 | // async fn completion(&self, _: CompletionParams) -> Result> { 145 | // tracing::debug!("Completion request"); 146 | // Ok(Some(CompletionResponse::Array(vec![ 147 | // CompletionItem::new_simple("Hello".to_string(), "Some detail".to_string()), 148 | // CompletionItem::new_simple("Bye".to_string(), "More detail".to_string()), 149 | // ]))) 150 | // } 151 | 152 | // TODO(@zkat): We'll use this when we actually do schema stuff. 153 | // async fn hover(&self, _: HoverParams) -> Result> { 154 | // tracing::debug!("Hover request"); 155 | // Ok(Some(Hover { 156 | // contents: HoverContents::Scalar(MarkedString::String("You're hovering!".to_string())), 157 | // range: None, 158 | // })) 159 | // } 160 | } 161 | 162 | fn char_to_position(char_idx: usize, rope: &Rope) -> Position { 163 | let line_idx = rope.char_to_line(char_idx); 164 | let line_char_idx = rope.line_to_char(line_idx); 165 | let column_idx = char_idx - line_char_idx; 166 | Position::new(line_idx as u32, column_idx as u32) 167 | } 168 | 169 | fn to_lsp_sev(sev: miette::Severity) -> DiagnosticSeverity { 170 | match sev { 171 | miette::Severity::Advice => DiagnosticSeverity::HINT, 172 | miette::Severity::Warning => DiagnosticSeverity::WARNING, 173 | miette::Severity::Error => DiagnosticSeverity::ERROR, 174 | } 175 | } 176 | 177 | #[tokio::main] 178 | async fn main() { 179 | tracing_subscriber::registry() 180 | .with( 181 | tracing_subscriber::fmt::layer() 182 | .map_writer(move |_| std::io::stderr) 183 | .with_ansi(false), 184 | ) 185 | .with(EnvFilter::from_default_env()) 186 | .init(); 187 | 188 | let stdin = tokio::io::stdin(); 189 | let stdout = tokio::io::stdout(); 190 | 191 | let (service, socket) = LspService::new(|client| Backend { 192 | client, 193 | document_map: DashMap::new(), 194 | }); 195 | Server::new(stdin, stdout, socket).serve(service).await; 196 | } 197 | --------------------------------------------------------------------------------