chore: switching to mfgames-project-setup-flake + reformat
This commit is contained in:
parent
32be8aad6e
commit
5702d4f9b8
234
.editorconfig
234
.editorconfig
|
@ -1,121 +1,123 @@
|
|||
root=true
|
||||
root = true
|
||||
["*"]
|
||||
charset = "utf-8"
|
||||
csharp_new_line_before_members_in_object_initializers = false
|
||||
csharp_preferred_modifier_order = "public, override, protected, internal, file, new, virtual, abstract, private, sealed, readonly, static, extern, unsafe, volatile, async, required:suggestion"
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = false
|
||||
csharp_space_after_cast = false
|
||||
csharp_style_var_elsewhere = "false:hint"
|
||||
csharp_style_var_for_built_in_types = "false:hint"
|
||||
csharp_style_var_when_type_is_apparent = "true:hint"
|
||||
curly_bracket_next_line = true
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = "true:hint"
|
||||
dotnet_style_predefined_type_for_member_access = "true:hint"
|
||||
dotnet_style_qualification_for_event = "true:hint"
|
||||
dotnet_style_qualification_for_field = "true:hint"
|
||||
dotnet_style_qualification_for_method = "true:hint"
|
||||
dotnet_style_qualification_for_property = "true:hint"
|
||||
dotnet_style_require_accessibility_modifiers = "for_non_interface_members:hint"
|
||||
end_of_line = "lf"
|
||||
indent_brace_style = "K&R"
|
||||
indent_size = 4
|
||||
indent_style = "space"
|
||||
insert_final_newline = true
|
||||
max_line_length = 80
|
||||
resharper_alignment_tab_fill_style = "optimal_fill"
|
||||
resharper_apply_on_completion = true
|
||||
resharper_blank_lines_after_control_transfer_statements = 1
|
||||
resharper_blank_lines_around_single_line_auto_property = 1
|
||||
resharper_blank_lines_around_single_line_property = 1
|
||||
resharper_blank_lines_before_block_statements = 1
|
||||
resharper_blank_lines_before_control_transfer_statements = 1
|
||||
resharper_blank_lines_before_single_line_comment = 1
|
||||
resharper_blank_lines_between_using_groups = 1
|
||||
resharper_braces_for_for = "required"
|
||||
resharper_braces_for_foreach = "required"
|
||||
resharper_braces_for_ifelse = "required"
|
||||
resharper_braces_for_while = "required"
|
||||
resharper_can_use_global_alias = false
|
||||
resharper_check_namespace_highlighting = "none"
|
||||
resharper_convert_to_auto_property_highlighting = "none"
|
||||
resharper_csharp_blank_lines_around_single_line_field = 1
|
||||
resharper_csharp_blank_lines_around_single_line_invocable = 1
|
||||
resharper_csharp_empty_block_style = "together_same_line"
|
||||
resharper_csharp_indent_style = "tab"
|
||||
resharper_csharp_insert_final_newline = true
|
||||
resharper_csharp_keep_blank_lines_in_code = 1
|
||||
resharper_csharp_keep_blank_lines_in_declarations = 1
|
||||
resharper_csharp_max_line_length = 100
|
||||
resharper_csharp_new_line_before_while = true
|
||||
resharper_csharp_use_indent_invocation_rpar = true
|
||||
resharper_csharp_wrap_extends_list_style = "chop_if_long"
|
||||
resharper_csharp_wrap_parameters_style = "chop_if_long"
|
||||
resharper_css_insert_final_newline = false
|
||||
resharper_enforce_line_ending_style = true
|
||||
resharper_html_insert_final_newline = false
|
||||
resharper_indent_nested_fixed_stmt = true
|
||||
resharper_js_indent_style = "spaces"
|
||||
resharper_js_insert_final_newline = true
|
||||
resharper_js_keep_blank_lines_in_code = 1
|
||||
resharper_js_stick_comment = false
|
||||
resharper_js_use_indent_from_vs = false
|
||||
resharper_js_wrap_before_binary_opsign = true
|
||||
resharper_js_wrap_chained_method_calls = "chop_if_long"
|
||||
resharper_keep_blank_lines_between_declarations = 1
|
||||
resharper_localizable_element_highlighting = "none"
|
||||
resharper_min_blank_lines_after_imports = 1
|
||||
resharper_place_attribute_on_same_line = false
|
||||
resharper_place_constructor_initializer_on_same_line = false
|
||||
resharper_place_expr_property_on_single_line = true
|
||||
resharper_place_simple_initializer_on_single_line = false
|
||||
resharper_place_type_constraints_on_same_line = false
|
||||
resharper_protobuf_insert_final_newline = false
|
||||
resharper_qualified_using_at_nested_scope = true
|
||||
resharper_redundant_comma_in_attribute_list_highlighting = "none"
|
||||
resharper_redundant_comma_in_enum_declaration_highlighting = "none"
|
||||
resharper_redundant_comma_in_initializer_highlighting = "none"
|
||||
resharper_resx_insert_final_newline = false
|
||||
resharper_space_within_single_line_array_initializer_braces = true
|
||||
resharper_string_compare_to_is_culture_specific_highlighting = "none"
|
||||
resharper_string_index_of_is_culture_specific_1_highlighting = "none"
|
||||
resharper_use_indents_from_main_language_in_file = false
|
||||
resharper_use_null_propagation_highlighting = "none"
|
||||
resharper_use_object_or_collection_initializer_highlighting = "hint"
|
||||
resharper_use_string_interpolation_highlighting = "hint"
|
||||
resharper_vb_insert_final_newline = false
|
||||
resharper_wrap_after_declaration_lpar = true
|
||||
resharper_wrap_after_invocation_lpar = true
|
||||
resharper_wrap_before_extends_colon = true
|
||||
resharper_wrap_before_first_type_parameter_constraint = true
|
||||
resharper_wrap_before_type_parameter_langle = true
|
||||
resharper_xml_insert_final_newline = false
|
||||
resharper_xmldoc_indent_child_elements = "ZeroIndent"
|
||||
resharper_xmldoc_indent_text = "ZeroIndent"
|
||||
resharper_xmldoc_insert_final_newline = false
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*]
|
||||
charset=utf-8
|
||||
csharp_new_line_before_members_in_object_initializers=false
|
||||
csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
|
||||
csharp_preserve_single_line_blocks=true
|
||||
csharp_preserve_single_line_statements=false
|
||||
csharp_space_after_cast=false
|
||||
csharp_style_var_elsewhere=false:hint
|
||||
csharp_style_var_for_built_in_types=false:hint
|
||||
csharp_style_var_when_type_is_apparent=true:hint
|
||||
curly_bracket_next_line=true
|
||||
dotnet_style_predefined_type_for_locals_parameters_members=true:hint
|
||||
dotnet_style_predefined_type_for_member_access=true:hint
|
||||
dotnet_style_qualification_for_event=true:hint
|
||||
dotnet_style_qualification_for_field=true:hint
|
||||
dotnet_style_qualification_for_method=true:hint
|
||||
dotnet_style_qualification_for_property=true:hint
|
||||
dotnet_style_require_accessibility_modifiers=for_non_interface_members:hint
|
||||
end_of_line=lf
|
||||
indent_brace_style=K&R
|
||||
indent_size=4
|
||||
indent_style=space
|
||||
insert_final_newline=true
|
||||
max_line_length=80
|
||||
resharper_alignment_tab_fill_style=optimal_fill
|
||||
resharper_apply_on_completion=true
|
||||
resharper_blank_lines_after_control_transfer_statements=1
|
||||
resharper_blank_lines_around_single_line_auto_property=1
|
||||
resharper_blank_lines_around_single_line_property=1
|
||||
resharper_blank_lines_before_single_line_comment=1
|
||||
resharper_blank_lines_between_using_groups=1
|
||||
resharper_braces_for_for=required
|
||||
resharper_braces_for_foreach=required
|
||||
resharper_braces_for_ifelse=required
|
||||
resharper_braces_for_while=required
|
||||
resharper_can_use_global_alias=false
|
||||
resharper_check_namespace_highlighting=none
|
||||
resharper_convert_to_auto_property_highlighting=none
|
||||
resharper_csharp_blank_lines_around_single_line_field=1
|
||||
resharper_csharp_blank_lines_around_single_line_invocable=1
|
||||
resharper_csharp_indent_style=tab
|
||||
resharper_csharp_insert_final_newline=true
|
||||
resharper_csharp_keep_blank_lines_in_code=1
|
||||
resharper_csharp_keep_blank_lines_in_declarations=1
|
||||
resharper_csharp_new_line_before_while=true
|
||||
resharper_csharp_use_indent_from_vs=false
|
||||
resharper_csharp_wrap_arguments_style=chop_if_long
|
||||
resharper_csharp_wrap_extends_list_style=chop_if_long
|
||||
resharper_csharp_wrap_parameters_style=chop_if_long
|
||||
resharper_css_insert_final_newline=false
|
||||
resharper_enforce_line_ending_style=true
|
||||
resharper_html_insert_final_newline=false
|
||||
resharper_indent_nested_fixed_stmt=true
|
||||
resharper_js_indent_style=tab
|
||||
resharper_js_insert_final_newline=true
|
||||
resharper_js_keep_blank_lines_in_code=1
|
||||
resharper_js_stick_comment=false
|
||||
resharper_js_use_indent_from_vs=false
|
||||
resharper_js_wrap_before_binary_opsign=true
|
||||
resharper_js_wrap_chained_method_calls=chop_if_long
|
||||
resharper_keep_blank_lines_between_declarations=1
|
||||
resharper_localizable_element_highlighting=none
|
||||
resharper_min_blank_lines_after_imports=1
|
||||
resharper_place_attribute_on_same_line=false
|
||||
resharper_place_constructor_initializer_on_same_line=false
|
||||
resharper_place_type_constraints_on_same_line=false
|
||||
resharper_protobuf_insert_final_newline=false
|
||||
resharper_qualified_using_at_nested_scope=true
|
||||
resharper_redundant_comma_in_attribute_list_highlighting=none
|
||||
resharper_redundant_comma_in_enum_declaration_highlighting=none
|
||||
resharper_redundant_comma_in_initializer_highlighting=none
|
||||
resharper_resx_insert_final_newline=false
|
||||
resharper_space_within_single_line_array_initializer_braces=true
|
||||
resharper_string_compare_to_is_culture_specific_highlighting=none
|
||||
resharper_string_index_of_is_culture_specific_1_highlighting=none
|
||||
resharper_use_indents_from_main_language_in_file=false
|
||||
resharper_use_null_propagation_highlighting=none
|
||||
resharper_use_object_or_collection_initializer_highlighting=hint
|
||||
resharper_use_string_interpolation_highlighting=hint
|
||||
resharper_vb_insert_final_newline=false
|
||||
resharper_wrap_after_declaration_lpar=true
|
||||
resharper_wrap_after_invocation_lpar=true
|
||||
resharper_wrap_before_extends_colon=true
|
||||
resharper_wrap_before_first_type_parameter_constraint=true
|
||||
resharper_wrap_before_type_parameter_langle=true
|
||||
resharper_xml_insert_final_newline=false
|
||||
resharper_xmldoc_indent_child_elements=ZeroIndent
|
||||
resharper_xmldoc_indent_text=ZeroIndent
|
||||
resharper_xmldoc_insert_final_newline=false
|
||||
tab_width=4
|
||||
trim_trailing_whitespace=true
|
||||
["*.cs"]
|
||||
indent_size = 4
|
||||
indent_style = "space"
|
||||
tab_width = 4
|
||||
|
||||
[*.md]
|
||||
max_line_length=off
|
||||
trim_trailing_whitespace=false
|
||||
["*.md"]
|
||||
max_line_length = "off"
|
||||
|
||||
[*.{appxmanifest,build,config,csproj,dbml,discomap,dtd,jsproj,lsproj,njsproj,nuspec,proj,props,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}]
|
||||
indent_size=2
|
||||
indent_style=space
|
||||
tab_width=2
|
||||
["*.{appxmanifest,build,config,csproj,dbml,discomap,dtd,jsproj,lsproj,njsproj,nuspec,proj,props,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}]"]
|
||||
indent_size = 2
|
||||
indent_style = "space"
|
||||
tab_width = 2
|
||||
|
||||
[*.{diff,patch}]
|
||||
end_of_line=unset
|
||||
indent_size=unset
|
||||
insert_final_newline=unset
|
||||
trim_trailing_whitespace=unset
|
||||
["package.json"]
|
||||
indent_size = 2
|
||||
indent_style = "space"
|
||||
tab_width = 2
|
||||
|
||||
[package.json]
|
||||
indent_size=2
|
||||
indent_style=space
|
||||
tab_width=2
|
||||
|
||||
[{LICENSES/**,LICENSE}]
|
||||
charset=unset
|
||||
end_of_line=unset
|
||||
indent_size=unset
|
||||
indent_style=unset
|
||||
insert_final_newline=unset
|
||||
trim_trailing_whitespace=unset
|
||||
["{LICENSES/**,LICENSE}"]
|
||||
charset = "unset"
|
||||
end_of_line = "unset"
|
||||
indent_size = "unset"
|
||||
indent_style = "unset"
|
||||
insert_final_newline = "unset"
|
||||
trim_trailing_whitespace = "unset"
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -23,6 +23,7 @@ TestResults/
|
|||
tests/artifacts/
|
||||
|
||||
# nixago: ignore-linked-files
|
||||
/.prettierrc.json
|
||||
/lefthook.yml
|
||||
/.conform.yaml
|
||||
/treefmt.toml
|
||||
/treefmt.toml
|
|
@ -17,24 +17,24 @@ diverse, inclusive, and healthy community.
|
|||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
|
|
133
CODE_OF_CONDUCT.md
Normal file
133
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,133 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official email address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
contact@mfgames.com.
|
||||
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
33
DCO.md
Normal file
33
DCO.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
|
@ -539,7 +539,7 @@ II.2.12 <HandlesEvent />
|
|||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseVarWhenEvident</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseVarWhenEvident</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/EditorConfig/EnableStyleCopSupport/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/FileHeader/FileHeaderText/@EntryValue"></s:String>
|
||||
|
||||
<s:Boolean x:Key="/Default/CodeStyle/LiveTemplatesUseVar/UseVar/@EntryValue">False</s:Boolean>
|
||||
|
||||
|
||||
|
@ -663,6 +663,7 @@ II.2.12 <HandlesEvent />
|
|||
<s:String x:Key="/Default/Environment/PerformanceGuide/SwitchBehaviour/=VCS/@EntryIndexedValue">LIVE_MONITOR</s:String>
|
||||
<s:String x:Key="/Default/Environment/PerformanceGuide/SwitchBehaviour/=VsBulb/@EntryIndexedValue">DO_NOTHING</s:String>
|
||||
<s:String x:Key="/Default/Environment/PerformanceGuide/SwitchBehaviour/=XAML_0020Designer/@EntryIndexedValue">LIVE_MONITOR</s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002ECodeCleanup_002EFileHeader_002EFileHeaderSettingsMigrate/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpFileLayoutPatternsUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
## Libraries
|
||||
|
||||
- [Gallium](./gallium/)
|
||||
- [Nitride](./nitride/)
|
||||
- [Gallium](./gallium/)
|
||||
- [Nitride](./nitride/)
|
||||
|
|
|
@ -4,17 +4,16 @@ namespace NitrideCopyFiles;
|
|||
|
||||
public class CopyFilesModule : Module
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
// This just registers all the non-static classes as singletons
|
||||
// within the system. We use lifetimes in other components depending
|
||||
// on how they are used, but in this case, we don't need it.
|
||||
builder.RegisterAssemblyTypes(
|
||||
this.GetType()
|
||||
.Assembly)
|
||||
.AsSelf()
|
||||
.AsImplementedInterfaces()
|
||||
.SingleInstance();
|
||||
}
|
||||
/// <inheritdoc />
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
// This just registers all the non-static classes as singletons
|
||||
// within the system. We use lifetimes in other components depending
|
||||
// on how they are used, but in this case, we don't need it.
|
||||
builder
|
||||
.RegisterAssemblyTypes(this.GetType().Assembly)
|
||||
.AsSelf()
|
||||
.AsImplementedInterfaces()
|
||||
.SingleInstance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
using MfGames.Gallium;
|
||||
using MfGames.Nitride;
|
||||
using MfGames.Nitride.IO.Contents;
|
||||
|
@ -16,97 +15,99 @@ namespace NitrideCopyFiles;
|
|||
/// </summary>
|
||||
public class CopyFilesPipeline : PipelineBase
|
||||
{
|
||||
private readonly AddPathPrefix addPathPrefix;
|
||||
private readonly AddPathPrefix addPathPrefix;
|
||||
|
||||
private readonly ClearDirectory clearDirectory;
|
||||
private readonly ClearDirectory clearDirectory;
|
||||
|
||||
private readonly ReadFiles readFiles;
|
||||
private readonly ReadFiles readFiles;
|
||||
|
||||
private readonly RemovePathPrefix removePathPrefix;
|
||||
private readonly RemovePathPrefix removePathPrefix;
|
||||
|
||||
private readonly WriteFiles writeFiles;
|
||||
private readonly WriteFiles writeFiles;
|
||||
|
||||
public CopyFilesPipeline(
|
||||
ReadFiles readFiles,
|
||||
ClearDirectory clearDirectory,
|
||||
WriteFiles writeFiles,
|
||||
RemovePathPrefix removePathPrefix,
|
||||
AddPathPrefix addPathPrefix)
|
||||
{
|
||||
// While we can configure these during runtime, it seems cleaner to
|
||||
// build them up during the constructor to call out the ones that
|
||||
// require runtime data.
|
||||
this.readFiles = readFiles.WithPattern("/input/**/*.txt");
|
||||
this.clearDirectory = clearDirectory.WithPath("/output");
|
||||
this.writeFiles = writeFiles;
|
||||
this.removePathPrefix = removePathPrefix.WithPathPrefix("/input");
|
||||
this.addPathPrefix = addPathPrefix.WithPathPrefix("/output");
|
||||
}
|
||||
public CopyFilesPipeline(
|
||||
ReadFiles readFiles,
|
||||
ClearDirectory clearDirectory,
|
||||
WriteFiles writeFiles,
|
||||
RemovePathPrefix removePathPrefix,
|
||||
AddPathPrefix addPathPrefix
|
||||
)
|
||||
{
|
||||
// While we can configure these during runtime, it seems cleaner to
|
||||
// build them up during the constructor to call out the ones that
|
||||
// require runtime data.
|
||||
this.readFiles = readFiles.WithPattern("/input/**/*.txt");
|
||||
this.clearDirectory = clearDirectory.WithPath("/output");
|
||||
this.writeFiles = writeFiles;
|
||||
this.removePathPrefix = removePathPrefix.WithPathPrefix("/input");
|
||||
this.addPathPrefix = addPathPrefix.WithPathPrefix("/output");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> _,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
// We don't care about the incoming entities which means we can
|
||||
// ignore them and use the entities from the ReadFiles operation
|
||||
// or we can union the entities pass in with the ReadFiles in case
|
||||
// we want to merge them.
|
||||
//
|
||||
// This will read all the files of the given pattern and return them
|
||||
// as an IEnumerable<Entity> with the Zio components (UPath and
|
||||
// binary contents) set. As a note, this doesn't actually read the
|
||||
// file, just create a pointer to where the file could be read from.
|
||||
//
|
||||
// The path component will always be the relative path to the root,
|
||||
// so `/input/a.txt` in this case since we only have one file.
|
||||
IEnumerable<Entity> entities = this.readFiles.Run();
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> _,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// We don't care about the incoming entities which means we can
|
||||
// ignore them and use the entities from the ReadFiles operation
|
||||
// or we can union the entities pass in with the ReadFiles in case
|
||||
// we want to merge them.
|
||||
//
|
||||
// This will read all the files of the given pattern and return them
|
||||
// as an IEnumerable<Entity> with the Zio components (UPath and
|
||||
// binary contents) set. As a note, this doesn't actually read the
|
||||
// file, just create a pointer to where the file could be read from.
|
||||
//
|
||||
// The path component will always be the relative path to the root,
|
||||
// so `/input/a.txt` in this case since we only have one file.
|
||||
IEnumerable<Entity> entities = this.readFiles.Run();
|
||||
|
||||
// Change the path. The path (Zio.UPath component) stays with the
|
||||
// entity which is why there is no root directory in the writeFiles
|
||||
// operation. Instead, we need to remove the `/input` and replace it
|
||||
// with the `/output`.
|
||||
//
|
||||
// We can do that with a RemovePathPrefix followed by an
|
||||
// AddPathPrefix, or use the more complex version of ChangePaths.
|
||||
// In this case, we are going for easy to learn, so we'll do the
|
||||
// pair.
|
||||
//
|
||||
// We are going to use the chain extension to make it easier to
|
||||
// read. Coming out of this, we will have one entity that fulfills:
|
||||
//
|
||||
// entity.Get<UPath> == "/output/a.txt"
|
||||
entities = entities
|
||||
.Run(this.removePathPrefix, cancellationToken)
|
||||
.Run(this.addPathPrefix, cancellationToken);
|
||||
// Change the path. The path (Zio.UPath component) stays with the
|
||||
// entity which is why there is no root directory in the writeFiles
|
||||
// operation. Instead, we need to remove the `/input` and replace it
|
||||
// with the `/output`.
|
||||
//
|
||||
// We can do that with a RemovePathPrefix followed by an
|
||||
// AddPathPrefix, or use the more complex version of ChangePaths.
|
||||
// In this case, we are going for easy to learn, so we'll do the
|
||||
// pair.
|
||||
//
|
||||
// We are going to use the chain extension to make it easier to
|
||||
// read. Coming out of this, we will have one entity that fulfills:
|
||||
//
|
||||
// entity.Get<UPath> == "/output/a.txt"
|
||||
entities = entities
|
||||
.Run(this.removePathPrefix, cancellationToken)
|
||||
.Run(this.addPathPrefix, cancellationToken);
|
||||
|
||||
// Then we write out the files to the output. First we make sure we
|
||||
// clear out the output. This operation performs an action when it
|
||||
// it is first entered, but otherwise passes all the inputs through.
|
||||
//
|
||||
// We can call the clear directory in three ways. The first is to call
|
||||
// the operation with:
|
||||
//
|
||||
// this.clearDirectory.Run()
|
||||
//
|
||||
// The other is to pass in the entities and get a new list of
|
||||
// modified ones out. In this case, clear doesn't make any changes,
|
||||
// but Entity objects are immutable, so we always work on the list
|
||||
// returned.
|
||||
//
|
||||
// entities = this.clearDirectory.Run(entity)
|
||||
//
|
||||
// The third way is to use an extension on entities which lets us
|
||||
// chain calls, ala Gulp's pipelines. The below code does this along
|
||||
// with writing the files to the output.
|
||||
entities = entities
|
||||
.Run(this.clearDirectory, cancellationToken)
|
||||
.Run(this.writeFiles, cancellationToken);
|
||||
// Then we write out the files to the output. First we make sure we
|
||||
// clear out the output. This operation performs an action when it
|
||||
// it is first entered, but otherwise passes all the inputs through.
|
||||
//
|
||||
// We can call the clear directory in three ways. The first is to call
|
||||
// the operation with:
|
||||
//
|
||||
// this.clearDirectory.Run()
|
||||
//
|
||||
// The other is to pass in the entities and get a new list of
|
||||
// modified ones out. In this case, clear doesn't make any changes,
|
||||
// but Entity objects are immutable, so we always work on the list
|
||||
// returned.
|
||||
//
|
||||
// entities = this.clearDirectory.Run(entity)
|
||||
//
|
||||
// The third way is to use an extension on entities which lets us
|
||||
// chain calls, ala Gulp's pipelines. The below code does this along
|
||||
// with writing the files to the output.
|
||||
entities = entities
|
||||
.Run(this.clearDirectory, cancellationToken)
|
||||
.Run(this.writeFiles, cancellationToken);
|
||||
|
||||
// If we are chaining this pipeline into another, we return the
|
||||
// entities. Otherwise, we can just return an empty list. The
|
||||
// pipeline is async, so it is wrapped in a task, but most
|
||||
// operations are not (or are both).
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
// If we are chaining this pipeline into another, we return the
|
||||
// entities. Otherwise, we can just return an empty list. The
|
||||
// pipeline is async, so it is wrapped in a task, but most
|
||||
// operations are not (or are both).
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Autofac;
|
||||
|
||||
using MfGames.IO.Extensions;
|
||||
using MfGames.Nitride;
|
||||
using MfGames.Nitride.IO.Setup;
|
||||
|
@ -15,41 +13,41 @@ namespace NitrideCopyFiles;
|
|||
/// </summary>
|
||||
public static class CopyFilesProgram
|
||||
{
|
||||
public static async Task<int> Main(string[] args)
|
||||
{
|
||||
// All of the builder methods are fluent in that they return the
|
||||
// builder to allow them to be chained. However, for documentation
|
||||
// purposes, we are going to split them apart to explain the details.
|
||||
var builder = new NitrideBuilder(args, ConfigureNitride);
|
||||
public static async Task<int> Main(string[] args)
|
||||
{
|
||||
// All of the builder methods are fluent in that they return the
|
||||
// builder to allow them to be chained. However, for documentation
|
||||
// purposes, we are going to split them apart to explain the details.
|
||||
var builder = new NitrideBuilder(args, ConfigureNitride);
|
||||
|
||||
// Filesystem access is provided by Zio, which allows for mutliple
|
||||
// folders to be combined together into a single unified file
|
||||
// system. At the moment, we set the "root" directory which will
|
||||
// contains all the paths, both input and output.
|
||||
//
|
||||
// Like Serilog, we use a number of extension methods on the builder
|
||||
// to inject functionality such as plugins and extensions. In this
|
||||
// case, we only need the Nitride.IO module so we use the `UseIO`
|
||||
// to inject the requisite modules and configure it.
|
||||
DirectoryInfo rootDir = typeof(CopyFilesProgram)
|
||||
.GetDirectory()!
|
||||
.FindGitRoot()!
|
||||
.GetDirectory("examples/NitrideCopyFiles");
|
||||
// Filesystem access is provided by Zio, which allows for mutliple
|
||||
// folders to be combined together into a single unified file
|
||||
// system. At the moment, we set the "root" directory which will
|
||||
// contains all the paths, both input and output.
|
||||
//
|
||||
// Like Serilog, we use a number of extension methods on the builder
|
||||
// to inject functionality such as plugins and extensions. In this
|
||||
// case, we only need the Nitride.IO module so we use the `UseIO`
|
||||
// to inject the requisite modules and configure it.
|
||||
DirectoryInfo rootDir = typeof(CopyFilesProgram)
|
||||
.GetDirectory()!
|
||||
.FindGitRoot()!
|
||||
.GetDirectory("examples/NitrideCopyFiles");
|
||||
|
||||
builder.UseIO(rootDir);
|
||||
builder.UseIO(rootDir);
|
||||
|
||||
// We use Autofac for the bulk of our registration handling. This
|
||||
// was mainly because we are more comfortable with Autofac, but it
|
||||
// also has a clean interface for handling some of the more esoteric
|
||||
// problems we've encountered.
|
||||
builder.ConfigureContainer(x => x.RegisterModule<CopyFilesModule>());
|
||||
// We use Autofac for the bulk of our registration handling. This
|
||||
// was mainly because we are more comfortable with Autofac, but it
|
||||
// also has a clean interface for handling some of the more esoteric
|
||||
// problems we've encountered.
|
||||
builder.ConfigureContainer(x => x.RegisterModule<CopyFilesModule>());
|
||||
|
||||
// Finally, we build the site generator object and run it.
|
||||
return await builder.RunAsync();
|
||||
}
|
||||
// Finally, we build the site generator object and run it.
|
||||
return await builder.RunAsync();
|
||||
}
|
||||
|
||||
private static void ConfigureNitride(NitrideConfiguration config)
|
||||
{
|
||||
config.AddLogPipelineCommandLineOption = true;
|
||||
}
|
||||
private static void ConfigureNitride(NitrideConfiguration config)
|
||||
{
|
||||
config.AddLogPipelineCommandLineOption = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,16 @@ namespace NitridePipelines;
|
|||
|
||||
public class NitridePipelinesModule : Module
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
// This just registers all the non-static classes as singletons
|
||||
// within the system. We use lifetimes in other components depending
|
||||
// on how they are used, but in this case, we don't need it.
|
||||
builder
|
||||
.RegisterAssemblyTypes(this.GetType().Assembly)
|
||||
.AsSelf()
|
||||
.AsImplementedInterfaces()
|
||||
.SingleInstance();
|
||||
}
|
||||
/// <inheritdoc />
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
// This just registers all the non-static classes as singletons
|
||||
// within the system. We use lifetimes in other components depending
|
||||
// on how they are used, but in this case, we don't need it.
|
||||
builder
|
||||
.RegisterAssemblyTypes(this.GetType().Assembly)
|
||||
.AsSelf()
|
||||
.AsImplementedInterfaces()
|
||||
.SingleInstance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Autofac;
|
||||
|
||||
using MfGames.IO.Extensions;
|
||||
using MfGames.Nitride;
|
||||
using MfGames.Nitride.IO.Setup;
|
||||
|
@ -15,22 +13,21 @@ namespace NitridePipelines;
|
|||
/// </summary>
|
||||
public static class NitridePipelinesProgram
|
||||
{
|
||||
public static async Task<int> Main(string[] args)
|
||||
{
|
||||
DirectoryInfo rootDir = typeof(NitridePipelinesProgram)
|
||||
.GetDirectory()!
|
||||
.FindGitRoot()!
|
||||
.GetDirectory("examples/NitridePipelines");
|
||||
public static async Task<int> Main(string[] args)
|
||||
{
|
||||
DirectoryInfo rootDir = typeof(NitridePipelinesProgram)
|
||||
.GetDirectory()!
|
||||
.FindGitRoot()!
|
||||
.GetDirectory("examples/NitridePipelines");
|
||||
|
||||
return await new NitrideBuilder(args, ConfigureNitride)
|
||||
.UseIO(rootDir)
|
||||
.ConfigureContainer(
|
||||
x => x.RegisterModule<NitridePipelinesModule>())
|
||||
.RunAsync();
|
||||
}
|
||||
return await new NitrideBuilder(args, ConfigureNitride)
|
||||
.UseIO(rootDir)
|
||||
.ConfigureContainer(x => x.RegisterModule<NitridePipelinesModule>())
|
||||
.RunAsync();
|
||||
}
|
||||
|
||||
private static void ConfigureNitride(NitrideConfiguration config)
|
||||
{
|
||||
config.AddLogPipelineCommandLineOption = true;
|
||||
}
|
||||
private static void ConfigureNitride(NitrideConfiguration config)
|
||||
{
|
||||
config.AddLogPipelineCommandLineOption = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,46 +2,38 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.Gallium;
|
||||
using MfGames.Nitride.Pipelines;
|
||||
|
||||
using Serilog;
|
||||
|
||||
using Zio;
|
||||
|
||||
namespace NitridePipelines.Pipelines;
|
||||
|
||||
public class DelayPipeline1 : PipelineBase
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly ILogger logger;
|
||||
|
||||
public DelayPipeline1(
|
||||
ILogger logger,
|
||||
InputPipeline1 input1)
|
||||
{
|
||||
this.logger = logger.ForContext<DelayPipeline1>();
|
||||
this.AddDependency(input1);
|
||||
}
|
||||
public DelayPipeline1(ILogger logger, InputPipeline1 input1)
|
||||
{
|
||||
this.logger = logger.ForContext<DelayPipeline1>();
|
||||
this.AddDependency(input1);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
entities = entities
|
||||
.Select(
|
||||
entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> entities,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
entities = entities.Select(entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
|
||||
this.logger.Information(
|
||||
"Delayed {Value}",
|
||||
entity.Get<UPath>());
|
||||
this.logger.Information("Delayed {Value}", entity.Get<UPath>());
|
||||
|
||||
return entity;
|
||||
});
|
||||
return entity;
|
||||
});
|
||||
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,53 +2,43 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.Gallium;
|
||||
using MfGames.Nitride.IO;
|
||||
using MfGames.Nitride.IO.Contents;
|
||||
|
||||
using Serilog;
|
||||
|
||||
using Zio;
|
||||
|
||||
namespace NitridePipelines.Pipelines;
|
||||
|
||||
public class InputPipeline1 : FileSystemWatchablePipelineBase
|
||||
{
|
||||
private readonly ReadFiles readFiles;
|
||||
private readonly ReadFiles readFiles;
|
||||
|
||||
public InputPipeline1(
|
||||
ILogger logger,
|
||||
IFileSystem fileSystem,
|
||||
ReadFiles readFiles)
|
||||
: base(logger, fileSystem)
|
||||
{
|
||||
this.readFiles = readFiles
|
||||
.WithPattern("/input/input1/*.txt");
|
||||
}
|
||||
public InputPipeline1(ILogger logger, IFileSystem fileSystem, ReadFiles readFiles)
|
||||
: base(logger, fileSystem)
|
||||
{
|
||||
this.readFiles = readFiles.WithPattern("/input/input1/*.txt");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override UPath WatchPath => "/input/input1";
|
||||
/// <inheritdoc />
|
||||
protected override UPath WatchPath => "/input/input1";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> _,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
IEnumerable<Entity> entities = this.readFiles
|
||||
.Run()
|
||||
.Select(
|
||||
entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> _,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
IEnumerable<Entity> entities = this.readFiles.Run()
|
||||
.Select(entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
|
||||
this.Logger.Information(
|
||||
"Read {Value}",
|
||||
entity.Get<UPath>());
|
||||
this.Logger.Information("Read {Value}", entity.Get<UPath>());
|
||||
|
||||
return entity;
|
||||
});
|
||||
return entity;
|
||||
});
|
||||
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,56 +2,46 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.Gallium;
|
||||
using MfGames.Nitride.IO;
|
||||
using MfGames.Nitride.IO.Contents;
|
||||
|
||||
using Serilog;
|
||||
|
||||
using Zio;
|
||||
|
||||
namespace NitridePipelines.Pipelines;
|
||||
|
||||
public class InputPipeline2 : FileSystemWatchablePipelineBase
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly ILogger logger;
|
||||
|
||||
private readonly ReadFiles readFiles;
|
||||
private readonly ReadFiles readFiles;
|
||||
|
||||
public InputPipeline2(
|
||||
ILogger logger,
|
||||
IFileSystem fileSystem,
|
||||
ReadFiles readFiles)
|
||||
: base(logger, fileSystem)
|
||||
{
|
||||
this.logger = logger.ForContext<InputPipeline2>();
|
||||
this.readFiles = readFiles
|
||||
.WithPattern("/input/input2/*.txt");
|
||||
}
|
||||
public InputPipeline2(ILogger logger, IFileSystem fileSystem, ReadFiles readFiles)
|
||||
: base(logger, fileSystem)
|
||||
{
|
||||
this.logger = logger.ForContext<InputPipeline2>();
|
||||
this.readFiles = readFiles.WithPattern("/input/input2/*.txt");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override UPath WatchPath => "/input/input2";
|
||||
/// <inheritdoc />
|
||||
protected override UPath WatchPath => "/input/input2";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> _,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
IEnumerable<Entity> entities = this.readFiles
|
||||
.Run()
|
||||
.Select(
|
||||
entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> _,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
IEnumerable<Entity> entities = this.readFiles.Run()
|
||||
.Select(entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
|
||||
this.logger.Information(
|
||||
"Read {Value}",
|
||||
entity.Get<UPath>());
|
||||
this.logger.Information("Read {Value}", entity.Get<UPath>());
|
||||
|
||||
return entity;
|
||||
});
|
||||
return entity;
|
||||
});
|
||||
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,47 +2,38 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.Gallium;
|
||||
using MfGames.Nitride.Pipelines;
|
||||
|
||||
using Serilog;
|
||||
|
||||
using Zio;
|
||||
|
||||
namespace NitridePipelines.Pipelines;
|
||||
|
||||
public class OutputPipeline1 : PipelineBase
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly ILogger logger;
|
||||
|
||||
public OutputPipeline1(
|
||||
ILogger logger,
|
||||
DelayPipeline1 delay1,
|
||||
InputPipeline2 input2)
|
||||
{
|
||||
this.logger = logger.ForContext<OutputPipeline1>();
|
||||
this.AddDependency(delay1, input2);
|
||||
}
|
||||
public OutputPipeline1(ILogger logger, DelayPipeline1 delay1, InputPipeline2 input2)
|
||||
{
|
||||
this.logger = logger.ForContext<OutputPipeline1>();
|
||||
this.AddDependency(delay1, input2);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
entities = entities
|
||||
.Select(
|
||||
entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> entities,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
entities = entities.Select(entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
|
||||
this.logger.Information(
|
||||
"Pretended to write {Value}",
|
||||
entity.Get<UPath>());
|
||||
this.logger.Information("Pretended to write {Value}", entity.Get<UPath>());
|
||||
|
||||
return entity;
|
||||
});
|
||||
return entity;
|
||||
});
|
||||
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,46 +2,38 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.Gallium;
|
||||
using MfGames.Nitride.Pipelines;
|
||||
|
||||
using Serilog;
|
||||
|
||||
using Zio;
|
||||
|
||||
namespace NitridePipelines.Pipelines;
|
||||
|
||||
public class OutputPipeline2 : PipelineBase
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly ILogger logger;
|
||||
|
||||
public OutputPipeline2(
|
||||
ILogger logger,
|
||||
InputPipeline2 input2)
|
||||
{
|
||||
this.logger = logger.ForContext<OutputPipeline2>();
|
||||
this.AddDependency(input2);
|
||||
}
|
||||
public OutputPipeline2(ILogger logger, InputPipeline2 input2)
|
||||
{
|
||||
this.logger = logger.ForContext<OutputPipeline2>();
|
||||
this.AddDependency(input2);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> entities,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
entities = entities
|
||||
.Select(
|
||||
entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
/// <inheritdoc />
|
||||
public override IAsyncEnumerable<Entity> RunAsync(
|
||||
IEnumerable<Entity> entities,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
entities = entities.Select(entity =>
|
||||
{
|
||||
Task.Delay(1000, cancellationToken).Wait(cancellationToken);
|
||||
|
||||
this.logger.Information(
|
||||
"Pretended to write {Value}",
|
||||
entity.Get<UPath>());
|
||||
this.logger.Information("Pretended to write {Value}", entity.Get<UPath>());
|
||||
|
||||
return entity;
|
||||
});
|
||||
return entity;
|
||||
});
|
||||
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
return entities.ToAsyncEnumerable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,88 +2,77 @@ using System;
|
|||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.ToolBuilder;
|
||||
using MfGames.ToolBuilder.Config;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace SampleTool.Commands;
|
||||
|
||||
public class ConfigCommand : Command, ICommandHandler, ITopCommand
|
||||
{
|
||||
private readonly ILogger<ConfigCommand> logger;
|
||||
private readonly ILogger<ConfigCommand> logger;
|
||||
|
||||
private readonly ConfigToolService service;
|
||||
private readonly ConfigToolService service;
|
||||
|
||||
private readonly Option<string> setOption;
|
||||
private readonly Option<string> setOption;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConfigCommand(
|
||||
ILoggerFactory loggerFactory,
|
||||
ConfigToolService service)
|
||||
: base(
|
||||
"config",
|
||||
"Sets and displays the configuration settings")
|
||||
{
|
||||
this.logger = loggerFactory.CreateLogger<ConfigCommand>();
|
||||
this.service = service;
|
||||
this.Handler = this;
|
||||
/// <inheritdoc />
|
||||
public ConfigCommand(ILoggerFactory loggerFactory, ConfigToolService service)
|
||||
: base("config", "Sets and displays the configuration settings")
|
||||
{
|
||||
this.logger = loggerFactory.CreateLogger<ConfigCommand>();
|
||||
this.service = service;
|
||||
this.Handler = this;
|
||||
|
||||
this.setOption = new Option<string>(
|
||||
"--set",
|
||||
"Sets the text value in the setting");
|
||||
this.setOption = new Option<string>("--set", "Sets the text value in the setting");
|
||||
|
||||
this.AddOption(this.setOption);
|
||||
}
|
||||
this.AddOption(this.setOption);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
// Get the settings and report that it was being created.
|
||||
ConfigCommandSettings settings =
|
||||
this.service.ReadDefaultConfigFile<ConfigCommandSettings>();
|
||||
/// <inheritdoc />
|
||||
public Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
// Get the settings and report that it was being created.
|
||||
ConfigCommandSettings settings =
|
||||
this.service.ReadDefaultConfigFile<ConfigCommandSettings>();
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
this.logger.LogInformation("Creating configuration file");
|
||||
settings = new ConfigCommandSettings();
|
||||
}
|
||||
if (settings == null)
|
||||
{
|
||||
this.logger.LogInformation("Creating configuration file");
|
||||
settings = new ConfigCommandSettings();
|
||||
}
|
||||
|
||||
// If we have a set command, then provide it.
|
||||
string value = context.ParseResult
|
||||
.GetValueForOption(this.setOption);
|
||||
// If we have a set command, then provide it.
|
||||
string value = context.ParseResult.GetValueForOption(this.setOption);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
settings.Value = value;
|
||||
}
|
||||
if (value != null)
|
||||
{
|
||||
settings.Value = value;
|
||||
}
|
||||
|
||||
// Increment the counter.
|
||||
settings.TimesRead++;
|
||||
// Increment the counter.
|
||||
settings.TimesRead++;
|
||||
|
||||
// Report the values.
|
||||
Console.WriteLine(
|
||||
JsonConvert.SerializeObject(settings, Formatting.Indented));
|
||||
// Report the values.
|
||||
Console.WriteLine(JsonConvert.SerializeObject(settings, Formatting.Indented));
|
||||
|
||||
// Write out the settings.
|
||||
this.service.WriteDefaultConfigFile(settings);
|
||||
// Write out the settings.
|
||||
this.service.WriteDefaultConfigFile(settings);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private class ConfigCommandSettings
|
||||
{
|
||||
public int TimesRead { get; set; }
|
||||
private class ConfigCommandSettings
|
||||
{
|
||||
public int TimesRead { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
}
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,42 +2,40 @@ using System;
|
|||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.ToolBuilder;
|
||||
|
||||
namespace SampleTool.Commands;
|
||||
|
||||
public class CrashCommand : Command, ICommandHandler, ITopCommand
|
||||
{
|
||||
private readonly Option<bool> messyOption;
|
||||
private readonly Option<bool> messyOption;
|
||||
|
||||
/// <inheritdoc />
|
||||
public CrashCommand()
|
||||
: base("crash", "Crash the application with an exception")
|
||||
{
|
||||
this.Handler = this;
|
||||
this.messyOption = new Option<bool>("--messy");
|
||||
/// <inheritdoc />
|
||||
public CrashCommand()
|
||||
: base("crash", "Crash the application with an exception")
|
||||
{
|
||||
this.Handler = this;
|
||||
this.messyOption = new Option<bool>("--messy");
|
||||
|
||||
this.AddOption(this.messyOption);
|
||||
}
|
||||
this.AddOption(this.messyOption);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
bool messy = context.ParseResult.GetValueForOption(this.messyOption);
|
||||
/// <inheritdoc />
|
||||
public Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
bool messy = context.ParseResult.GetValueForOption(this.messyOption);
|
||||
|
||||
if (messy)
|
||||
{
|
||||
throw new Exception(
|
||||
"This command crashed messily as requested.");
|
||||
}
|
||||
if (messy)
|
||||
{
|
||||
throw new Exception("This command crashed messily as requested.");
|
||||
}
|
||||
|
||||
throw new ToolException("This command crashed as requested.");
|
||||
}
|
||||
throw new ToolException("This command crashed as requested.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,97 +1,84 @@
|
|||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.ToolBuilder;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using ILogger = Serilog.ILogger;
|
||||
|
||||
namespace SampleTool.Commands;
|
||||
|
||||
public class LogCommand : Command, ICommandHandler, ITopCommand
|
||||
{
|
||||
private readonly ILogger<LogCommand> extensionLogger;
|
||||
private readonly ILogger<LogCommand> extensionLogger;
|
||||
|
||||
private readonly ILogger serilogContextLogger;
|
||||
private readonly ILogger serilogContextLogger;
|
||||
|
||||
private readonly ILogger serilogLogger;
|
||||
private readonly ILogger serilogLogger;
|
||||
|
||||
/// <inheritdoc />
|
||||
public LogCommand(
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger serilogLogger)
|
||||
: base(
|
||||
"log",
|
||||
"Shows various logging messages using Serilog and Microsoft")
|
||||
{
|
||||
this.serilogLogger = serilogLogger;
|
||||
this.serilogContextLogger = serilogLogger.ForContext<LogCommand>();
|
||||
this.extensionLogger = loggerFactory.CreateLogger<LogCommand>();
|
||||
this.Handler = this;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public LogCommand(ILoggerFactory loggerFactory, ILogger serilogLogger)
|
||||
: base("log", "Shows various logging messages using Serilog and Microsoft")
|
||||
{
|
||||
this.serilogLogger = serilogLogger;
|
||||
this.serilogContextLogger = serilogLogger.ForContext<LogCommand>();
|
||||
this.extensionLogger = loggerFactory.CreateLogger<LogCommand>();
|
||||
this.Handler = this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
// Show the serilog logging.
|
||||
this.serilogLogger.Verbose("Serilog Verbose()");
|
||||
this.serilogLogger.Debug("Serilog Debug()");
|
||||
this.serilogLogger.Information("Serilog Information()");
|
||||
this.serilogLogger.Warning("Serilog Warning()");
|
||||
this.serilogLogger.Error("Serilog Error()");
|
||||
this.serilogLogger.Fatal("Serilog Fatal()");
|
||||
/// <inheritdoc />
|
||||
public Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
// Show the serilog logging.
|
||||
this.serilogLogger.Verbose("Serilog Verbose()");
|
||||
this.serilogLogger.Debug("Serilog Debug()");
|
||||
this.serilogLogger.Information("Serilog Information()");
|
||||
this.serilogLogger.Warning("Serilog Warning()");
|
||||
this.serilogLogger.Error("Serilog Error()");
|
||||
this.serilogLogger.Fatal("Serilog Fatal()");
|
||||
|
||||
// Show serilog with context.
|
||||
this.serilogContextLogger.Information(
|
||||
"Serilog Information() with context");
|
||||
// Show serilog with context.
|
||||
this.serilogContextLogger.Information("Serilog Information() with context");
|
||||
|
||||
// Show the extension logging.
|
||||
this.extensionLogger.LogTrace(
|
||||
"System.Extension.Logging LogTrace");
|
||||
this.extensionLogger.LogDebug(
|
||||
"System.Extension.Logging LogDebug");
|
||||
this.extensionLogger.LogInformation(
|
||||
"System.Extension.Logging LogInformation");
|
||||
this.extensionLogger.LogWarning(
|
||||
"System.Extension.Logging LogWarning");
|
||||
this.extensionLogger.LogError(
|
||||
"System.Extension.Logging LogError");
|
||||
this.extensionLogger.LogCritical(
|
||||
"System.Extension.Logging LogCritical");
|
||||
// Show the extension logging.
|
||||
this.extensionLogger.LogTrace("System.Extension.Logging LogTrace");
|
||||
this.extensionLogger.LogDebug("System.Extension.Logging LogDebug");
|
||||
this.extensionLogger.LogInformation("System.Extension.Logging LogInformation");
|
||||
this.extensionLogger.LogWarning("System.Extension.Logging LogWarning");
|
||||
this.extensionLogger.LogError("System.Extension.Logging LogError");
|
||||
this.extensionLogger.LogCritical("System.Extension.Logging LogCritical");
|
||||
|
||||
// Show Serilog working through logging extensions.
|
||||
var hash = new
|
||||
{
|
||||
Number = 1,
|
||||
String = "String",
|
||||
Inner = new { Nested = true }
|
||||
};
|
||||
// Show Serilog working through logging extensions.
|
||||
var hash = new
|
||||
{
|
||||
Number = 1,
|
||||
String = "String",
|
||||
Inner = new { Nested = true }
|
||||
};
|
||||
|
||||
this.serilogLogger.Information(
|
||||
"Serilog Contextual parameters {Name} and {Quotes:l}",
|
||||
"extension logger",
|
||||
"without quotes");
|
||||
this.serilogLogger.Information(
|
||||
"Serilog Contextual nested object {@Nested}",
|
||||
hash);
|
||||
this.serilogLogger.Information(
|
||||
"Serilog Contextual parameters {Name} and {Quotes:l}",
|
||||
"extension logger",
|
||||
"without quotes"
|
||||
);
|
||||
this.serilogLogger.Information("Serilog Contextual nested object {@Nested}", hash);
|
||||
|
||||
this.extensionLogger.LogInformation(
|
||||
"System.Extension.Logging parameters {Name} and {Quotes:l}",
|
||||
"extension logger",
|
||||
"without quotes");
|
||||
this.extensionLogger.LogInformation(
|
||||
"System.Extension.Logging nested object {@Nested}",
|
||||
hash);
|
||||
this.extensionLogger.LogInformation(
|
||||
"System.Extension.Logging parameters {Name} and {Quotes:l}",
|
||||
"extension logger",
|
||||
"without quotes"
|
||||
);
|
||||
this.extensionLogger.LogInformation(
|
||||
"System.Extension.Logging nested object {@Nested}",
|
||||
hash
|
||||
);
|
||||
|
||||
// We're good.
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
// We're good.
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,81 +11,77 @@ using System.CommandLine;
|
|||
using System.CommandLine.Invocation;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.ToolBuilder;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Spectre.Console;
|
||||
|
||||
namespace SampleTool.Commands;
|
||||
|
||||
public class SpectreCommand : Command, ICommandHandler, ITopCommand
|
||||
{
|
||||
private readonly ILogger<LogCommand> logger;
|
||||
private readonly ILogger<LogCommand> logger;
|
||||
|
||||
/// <inheritdoc />
|
||||
public SpectreCommand(ILoggerFactory loggerFactory)
|
||||
: base("spectre", "Shows various SpectreConsole features")
|
||||
{
|
||||
this.logger = loggerFactory.CreateLogger<LogCommand>();
|
||||
this.Handler = this;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public SpectreCommand(ILoggerFactory loggerFactory)
|
||||
: base("spectre", "Shows various SpectreConsole features")
|
||||
{
|
||||
this.logger = loggerFactory.CreateLogger<LogCommand>();
|
||||
this.Handler = this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
// Display a message ahead of this.
|
||||
this.logger.LogInformation("Before things happened.");
|
||||
/// <inheritdoc />
|
||||
public async Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
// Display a message ahead of this.
|
||||
this.logger.LogInformation("Before things happened.");
|
||||
|
||||
// Show a progress bar.
|
||||
CancellationToken cancellationToken = context.GetCancellationToken();
|
||||
DateTime last = DateTime.UtcNow;
|
||||
// Show a progress bar.
|
||||
CancellationToken cancellationToken = context.GetCancellationToken();
|
||||
DateTime last = DateTime.UtcNow;
|
||||
|
||||
await AnsiConsole.Progress()
|
||||
.AutoClear(true)
|
||||
.StartAsync(
|
||||
async ctx =>
|
||||
{
|
||||
ProgressTask task1 = ctx.AddTask("[green]Fast Task[/]");
|
||||
ProgressTask task2 = ctx.AddTask("[green]Slow Task[/]");
|
||||
await AnsiConsole
|
||||
.Progress()
|
||||
.AutoClear(true)
|
||||
.StartAsync(async ctx =>
|
||||
{
|
||||
ProgressTask task1 = ctx.AddTask("[green]Fast Task[/]");
|
||||
ProgressTask task2 = ctx.AddTask("[green]Slow Task[/]");
|
||||
|
||||
while (!ctx.IsFinished)
|
||||
{
|
||||
// See if we're cancelled.
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (!ctx.IsFinished)
|
||||
{
|
||||
// See if we're cancelled.
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Simulate some work
|
||||
await Task.Delay(25, cancellationToken);
|
||||
// Simulate some work
|
||||
await Task.Delay(25, cancellationToken);
|
||||
|
||||
if (DateTime.UtcNow - last
|
||||
> TimeSpan.FromMilliseconds(500))
|
||||
{
|
||||
this.logger.LogWarning("Working...");
|
||||
last = DateTime.UtcNow;
|
||||
}
|
||||
if (DateTime.UtcNow - last > TimeSpan.FromMilliseconds(500))
|
||||
{
|
||||
this.logger.LogWarning("Working...");
|
||||
last = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await Task.Delay(25, cancellationToken);
|
||||
await Task.Delay(25, cancellationToken);
|
||||
|
||||
// Increment
|
||||
task1.Increment(2.0);
|
||||
task2.Increment(1.0);
|
||||
}
|
||||
});
|
||||
// Increment
|
||||
task1.Increment(2.0);
|
||||
task2.Increment(1.0);
|
||||
}
|
||||
});
|
||||
|
||||
// Report we're done.
|
||||
this.logger.LogInformation("Done");
|
||||
// Report we're done.
|
||||
this.logger.LogInformation("Done");
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.CommandLine;
|
|||
using System.CommandLine.Invocation;
|
||||
using System.Data;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using MfGames.ToolBuilder;
|
||||
using MfGames.ToolBuilder.Tables;
|
||||
|
||||
|
@ -11,49 +10,46 @@ namespace SampleTool.Commands;
|
|||
|
||||
public class TableCommand : Command, ICommandHandler, ITopCommand
|
||||
{
|
||||
private readonly DataTable table;
|
||||
private readonly DataTable table;
|
||||
|
||||
private readonly TableToolService tableService;
|
||||
private readonly TableToolService tableService;
|
||||
|
||||
/// <inheritdoc />
|
||||
public TableCommand(TableToolService.Factory tableService)
|
||||
: base("table", "Display a Markdown table")
|
||||
{
|
||||
// Create the table structure.
|
||||
this.table = new DataTable();
|
||||
this.table.Columns.Add("DefaultString", typeof(string));
|
||||
this.table.Columns.Add("DefaultInt32", typeof(int));
|
||||
this.table.Columns.Add("HiddenString", typeof(string));
|
||||
/// <inheritdoc />
|
||||
public TableCommand(TableToolService.Factory tableService)
|
||||
: base("table", "Display a Markdown table")
|
||||
{
|
||||
// Create the table structure.
|
||||
this.table = new DataTable();
|
||||
this.table.Columns.Add("DefaultString", typeof(string));
|
||||
this.table.Columns.Add("DefaultInt32", typeof(int));
|
||||
this.table.Columns.Add("HiddenString", typeof(string));
|
||||
|
||||
// Create the table service for formatting and displaying results.
|
||||
this.tableService = tableService(
|
||||
this.table,
|
||||
new List<string>
|
||||
{
|
||||
"DefaultString",
|
||||
"DefaultInt32",
|
||||
})
|
||||
.Attach(this);
|
||||
// Create the table service for formatting and displaying results.
|
||||
this.tableService = tableService(
|
||||
this.table,
|
||||
new List<string> { "DefaultString", "DefaultInt32", }
|
||||
)
|
||||
.Attach(this);
|
||||
|
||||
// This class handles the command.
|
||||
this.Handler = this;
|
||||
}
|
||||
// This class handles the command.
|
||||
this.Handler = this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public int Invoke(InvocationContext context)
|
||||
{
|
||||
return this.InvokeAsync(context).Result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
this.table.Rows.Add("Row 1", 1, "Hidden 1");
|
||||
this.table.Rows.Add("Row 2", 10, "Hidden 2");
|
||||
this.table.Rows.Add("Row 3", 100, "Hidden 3");
|
||||
/// <inheritdoc />
|
||||
public Task<int> InvokeAsync(InvocationContext context)
|
||||
{
|
||||
this.table.Rows.Add("Row 1", 1, "Hidden 1");
|
||||
this.table.Rows.Add("Row 2", 10, "Hidden 2");
|
||||
this.table.Rows.Add("Row 3", 100, "Hidden 3");
|
||||
|
||||
this.tableService.Write(context);
|
||||
this.tableService.Write(context);
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
using Autofac;
|
||||
|
||||
using MfGames.ToolBuilder;
|
||||
using MfGames.ToolBuilder.Config;
|
||||
using MfGames.ToolBuilder.Tables;
|
||||
|
@ -10,19 +8,19 @@ namespace SampleTool;
|
|||
|
||||
public static class Program
|
||||
{
|
||||
public static async Task<int> Main(string[] args)
|
||||
{
|
||||
return await ToolBoxBuilder
|
||||
.Create(args)
|
||||
.UseUserConfiguration("mfgames-toolbuilder-sample")
|
||||
.ConfigureContainer(ConfigureContainer)
|
||||
.Build()
|
||||
.RunAsync();
|
||||
}
|
||||
public static async Task<int> Main(string[] args)
|
||||
{
|
||||
return await ToolBoxBuilder
|
||||
.Create(args)
|
||||
.UseUserConfiguration("mfgames-toolbuilder-sample")
|
||||
.ConfigureContainer(ConfigureContainer)
|
||||
.Build()
|
||||
.RunAsync();
|
||||
}
|
||||
|
||||
private static void ConfigureContainer(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterModule<SampleToolModule>();
|
||||
builder.RegisterModule<ToolBuilderTablesModule>();
|
||||
}
|
||||
private static void ConfigureContainer(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterModule<SampleToolModule>();
|
||||
builder.RegisterModule<ToolBuilderTablesModule>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.Linq;
|
||||
|
||||
using Autofac;
|
||||
|
||||
using MfGames.ToolBuilder;
|
||||
|
||||
namespace SampleTool;
|
||||
|
@ -14,44 +12,38 @@ namespace SampleTool;
|
|||
/// </summary>
|
||||
public class SampleToolModule : Module
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder
|
||||
.RegisterAssemblyTypes(this.GetType().Assembly)
|
||||
.AsSelf()
|
||||
.AsImplementedInterfaces();
|
||||
/// <inheritdoc />
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterAssemblyTypes(this.GetType().Assembly).AsSelf().AsImplementedInterfaces();
|
||||
|
||||
builder
|
||||
.Register(
|
||||
c =>
|
||||
{
|
||||
// Create the top-level command.
|
||||
var root = new RootCommand
|
||||
{
|
||||
Name = "sample-tool",
|
||||
Description =
|
||||
"A sample tool that demonstrates functionality",
|
||||
};
|
||||
builder
|
||||
.Register(c =>
|
||||
{
|
||||
// Create the top-level command.
|
||||
var root = new RootCommand
|
||||
{
|
||||
Name = "sample-tool",
|
||||
Description = "A sample tool that demonstrates functionality",
|
||||
};
|
||||
|
||||
// Add in the top-level commands.
|
||||
var commandList = c.Resolve<IList<ITopCommand>>()
|
||||
.Cast<Command>()
|
||||
.ToList();
|
||||
// Add in the top-level commands.
|
||||
var commandList = c.Resolve<IList<ITopCommand>>().Cast<Command>().ToList();
|
||||
|
||||
if (commandList.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Cannot create a tool without at least one command extending System.CommandLine.Command");
|
||||
}
|
||||
if (commandList.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Cannot create a tool without at least one command extending System.CommandLine.Command"
|
||||
);
|
||||
}
|
||||
|
||||
foreach (Command command in commandList)
|
||||
{
|
||||
root.AddCommand(command);
|
||||
}
|
||||
foreach (Command command in commandList)
|
||||
{
|
||||
root.AddCommand(command);
|
||||
}
|
||||
|
||||
return root;
|
||||
})
|
||||
.AsSelf();
|
||||
}
|
||||
return root;
|
||||
})
|
||||
.AsSelf();
|
||||
}
|
||||
}
|
||||
|
|
771
flake.lock
771
flake.lock
|
@ -1,136 +1,12 @@
|
|||
{
|
||||
"nodes": {
|
||||
"blank": {
|
||||
"locked": {
|
||||
"lastModified": 1625557891,
|
||||
"narHash": "sha256-O8/MWsPBGhhyPoPLHZAuoZiiHo9q6FLlEeIDEXuj6T4=",
|
||||
"owner": "divnix",
|
||||
"repo": "blank",
|
||||
"rev": "5a5d2684073d9f563072ed07c871d577a6c614a8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "divnix",
|
||||
"repo": "blank",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"crane": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"paisano-mdbook-preprocessor",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1676162383,
|
||||
"narHash": "sha256-krUCKdz7ebHlFYm/A7IbKDnj2ZmMMm3yIEQcooqm7+E=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "6fb400ec631b22ccdbc7090b38207f7fb5cfb5f2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devshell": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"std",
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1682700442,
|
||||
"narHash": "sha256-qjaAAcCYgp1pBBG7mY9z95ODUBZMtUpf0Qp3Gt/Wha0=",
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"rev": "fb6673fe9fe4409e3f43ca86968261e970918a83",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "devshell",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"dmerge": {
|
||||
"inputs": {
|
||||
"haumea": "haumea",
|
||||
"nixlib": "nixlib",
|
||||
"yants": [
|
||||
"std",
|
||||
"yants"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1686862774,
|
||||
"narHash": "sha256-ojGtRQ9pIOUrxsQEuEPerUkqIJEuod9hIflfNkY+9CE=",
|
||||
"owner": "divnix",
|
||||
"repo": "dmerge",
|
||||
"rev": "9f7f7a8349d33d7bd02e0f2b484b1f076e503a96",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "divnix",
|
||||
"ref": "0.2.1",
|
||||
"repo": "dmerge",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1677306201,
|
||||
"narHash": "sha256-VZ9x7qdTosFvVsrpgFHrtYfT6PU3yMIs7NRYn9ELapI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "0923f0c162f65ae40261ec940406049726cfeab4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -141,11 +17,11 @@
|
|||
},
|
||||
"flake-utils_2": {
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -154,97 +30,296 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"haumea": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"dmerge",
|
||||
"nixlib"
|
||||
]
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"locked": {
|
||||
"lastModified": 1685133229,
|
||||
"narHash": "sha256-FePm/Gi9PBSNwiDFq3N+DWdfxFq0UKsVVTJS3cQPn94=",
|
||||
"owner": "nix-community",
|
||||
"repo": "haumea",
|
||||
"rev": "34dd58385092a23018748b50f9b23de6266dffc2",
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "v0.2.2",
|
||||
"repo": "haumea",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"incl": {
|
||||
"inputs": {
|
||||
"nixlib": [
|
||||
"std",
|
||||
"dmerge",
|
||||
"nixlib"
|
||||
]
|
||||
},
|
||||
"flake-utils_4": {
|
||||
"locked": {
|
||||
"lastModified": 1669263024,
|
||||
"narHash": "sha256-E/+23NKtxAqYG/0ydYgxlgarKnxmDbg6rCMWnOBqn9Q=",
|
||||
"owner": "divnix",
|
||||
"repo": "incl",
|
||||
"rev": "ce7bebaee048e4cd7ebdb4cee7885e00c4e2abca",
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "divnix",
|
||||
"repo": "incl",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"n2c": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"std",
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"flake-utils_5": {
|
||||
"locked": {
|
||||
"lastModified": 1685771919,
|
||||
"narHash": "sha256-3lVKWrhNXjHJB6QkZ2SJaOs4X/mmYXtY6ovPVpDMOHc=",
|
||||
"owner": "nlewo",
|
||||
"repo": "nix2container",
|
||||
"rev": "95e2220911874064b5d809f8d35f7835184c4ddf",
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nlewo",
|
||||
"repo": "nix2container",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_6": {
|
||||
"locked": {
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_7": {
|
||||
"locked": {
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_8": {
|
||||
"locked": {
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_9": {
|
||||
"locked": {
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mfgames-project-setup": {
|
||||
"inputs": {
|
||||
"nixago": "nixago",
|
||||
"nixago-exts": "nixago-exts_3",
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709701991,
|
||||
"narHash": "sha256-aioBatPisIMfmVUq50g9M74GidTqgRpA+PVXuL6NYAo=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "9c50fe4984c346cec825c2875e1ba81ec385f5b1",
|
||||
"revCount": 15,
|
||||
"type": "git",
|
||||
"url": "https://src.mfgames.com/nixos-contrib/mfgames-project-setup-flake.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://src.mfgames.com/nixos-contrib/mfgames-project-setup-flake.git"
|
||||
}
|
||||
},
|
||||
"nixago": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"std",
|
||||
"flake-utils"
|
||||
],
|
||||
"nixago-exts": [
|
||||
"std",
|
||||
"blank"
|
||||
],
|
||||
"flake-utils": "flake-utils",
|
||||
"nixago-exts": "nixago-exts",
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"mfgames-project-setup",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1683210100,
|
||||
"narHash": "sha256-bhGDOlkWtlhVECpoOog4fWiFJmLCpVEg09a40aTjCbw=",
|
||||
"lastModified": 1687381756,
|
||||
"narHash": "sha256-IUMIlYfrvj7Yli4H2vvyig8HEPpfCeMaE6+kBGPzFyk=",
|
||||
"owner": "jmgilman",
|
||||
"repo": "nixago",
|
||||
"rev": "dacceb10cace103b3e66552ec9719fa0d33c0dc9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "jmgilman",
|
||||
"repo": "nixago",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixago-exts": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixago": "nixago_2",
|
||||
"nixpkgs": [
|
||||
"mfgames-project-setup",
|
||||
"nixago",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1676070308,
|
||||
"narHash": "sha256-QaJ65oc2l8iwQIGWUJ0EKjCeSuuCM/LqR8RauxZUUkc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago-extensions",
|
||||
"rev": "e5380cb0456f4ea3c86cf94e3039eb856bf07d0b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago-extensions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixago-exts_2": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_4",
|
||||
"nixago": "nixago_3",
|
||||
"nixpkgs": [
|
||||
"mfgames-project-setup",
|
||||
"nixago",
|
||||
"nixago-exts",
|
||||
"nixago",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1655508669,
|
||||
"narHash": "sha256-BDDdo5dZQMmwNH/GNacy33nPBnCpSIydWFPZs0kkj/g=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago-extensions",
|
||||
"rev": "3022a932ce109258482ecc6568c163e8d0b426aa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago-extensions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixago-exts_3": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_6",
|
||||
"nixago": "nixago_4",
|
||||
"nixpkgs": [
|
||||
"mfgames-project-setup",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1676070308,
|
||||
"narHash": "sha256-QaJ65oc2l8iwQIGWUJ0EKjCeSuuCM/LqR8RauxZUUkc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago-extensions",
|
||||
"rev": "e5380cb0456f4ea3c86cf94e3039eb856bf07d0b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago-extensions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixago-exts_4": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_8",
|
||||
"nixago": "nixago_5",
|
||||
"nixpkgs": [
|
||||
"mfgames-project-setup",
|
||||
"nixago-exts",
|
||||
"nixago",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1655508669,
|
||||
"narHash": "sha256-BDDdo5dZQMmwNH/GNacy33nPBnCpSIydWFPZs0kkj/g=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago-extensions",
|
||||
"rev": "3022a932ce109258482ecc6568c163e8d0b426aa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago-extensions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixago_2": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_3",
|
||||
"nixago-exts": "nixago-exts_2",
|
||||
"nixpkgs": [
|
||||
"mfgames-project-setup",
|
||||
"nixago",
|
||||
"nixago-exts",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1676070010,
|
||||
"narHash": "sha256-iYzJIWptE1EUD8VINAg66AAMUajizg8JUYN3oBmb8no=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago",
|
||||
"rev": "1da60ad9412135f9ed7a004669fdcf3d378ec630",
|
||||
"rev": "d480ba6c0c16e2c5c0bd2122852d6a0c9ad1ed0e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "rename-config-data",
|
||||
"repo": "nixago",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixago_3": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_5",
|
||||
"nixpkgs": [
|
||||
"mfgames-project-setup",
|
||||
"nixago",
|
||||
"nixago-exts",
|
||||
"nixago",
|
||||
"nixago-exts",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1655405483,
|
||||
"narHash": "sha256-Crd49aZWNrpczlRTOwWGfwBMsTUoG9vlHDKQC7cx264=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago",
|
||||
"rev": "e6a9566c18063db5b120e69e048d3627414e327d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -253,284 +328,88 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixlib": {
|
||||
"nixago_4": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_7",
|
||||
"nixago-exts": "nixago-exts_4",
|
||||
"nixpkgs": [
|
||||
"mfgames-project-setup",
|
||||
"nixago-exts",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681001314,
|
||||
"narHash": "sha256-5sDnCLdrKZqxLPK4KA8+f4A3YKO/u6ElpMILvX0g72c=",
|
||||
"lastModified": 1676070010,
|
||||
"narHash": "sha256-iYzJIWptE1EUD8VINAg66AAMUajizg8JUYN3oBmb8no=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "367c0e1086a4eb4502b24d872cea2c7acdd557f4",
|
||||
"repo": "nixago",
|
||||
"rev": "d480ba6c0c16e2c5c0bd2122852d6a0c9ad1ed0e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"ref": "rename-config-data",
|
||||
"repo": "nixago",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixago_5": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_9",
|
||||
"nixpkgs": [
|
||||
"mfgames-project-setup",
|
||||
"nixago-exts",
|
||||
"nixago",
|
||||
"nixago-exts",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1655405483,
|
||||
"narHash": "sha256-Crd49aZWNrpczlRTOwWGfwBMsTUoG9vlHDKQC7cx264=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago",
|
||||
"rev": "e6a9566c18063db5b120e69e048d3627414e327d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixago",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1693565476,
|
||||
"narHash": "sha256-ya00zHt7YbPo3ve/wNZ/6nts61xt7wK/APa6aZAfey0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "aa8aa7e2ea35ce655297e8322dc82bf77a31d04b",
|
||||
"type": "github"
|
||||
"lastModified": 1706098335,
|
||||
"narHash": "sha256-r3dWjT8P9/Ah5m5ul4WqIWD8muj5F+/gbCdjiNVBKmU=",
|
||||
"rev": "a77ab169a83a4175169d78684ddd2e54486ac651",
|
||||
"revCount": 554858,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2311.554858%2Brev-a77ab169a83a4175169d78684ddd2e54486ac651/018d46f0-798f-71dc-a8c5-4689c46f7d12/source.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
"type": "tarball",
|
||||
"url": "https://flakehub.com/f/NixOS/nixpkgs/%2A.tar.gz"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1677063315,
|
||||
"narHash": "sha256-qiB4ajTeAOVnVSAwCNEEkoybrAlA+cpeiBxLobHndE8=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "988cc958c57ce4350ec248d2d53087777f9e1949",
|
||||
"type": "github"
|
||||
"lastModified": 1709569716,
|
||||
"narHash": "sha256-iOR44RU4jQ+YPGrn+uQeYAp7Xo7Z/+gT+wXJoGxxLTY=",
|
||||
"rev": "617579a787259b9a6419492eaac670a5f7663917",
|
||||
"revCount": 556422,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2311.556422%2Brev-617579a787259b9a6419492eaac670a5f7663917/018e0df2-b0f7-7a27-af1a-04150ef0f2c7/source.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nosys": {
|
||||
"locked": {
|
||||
"lastModified": 1668010795,
|
||||
"narHash": "sha256-JBDVBnos8g0toU7EhIIqQ1If5m/nyBqtHhL3sicdPwI=",
|
||||
"owner": "divnix",
|
||||
"repo": "nosys",
|
||||
"rev": "feade0141487801c71ff55623b421ed535dbdefa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "divnix",
|
||||
"repo": "nosys",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"paisano": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nosys": "nosys",
|
||||
"yants": [
|
||||
"std",
|
||||
"yants"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1686862844,
|
||||
"narHash": "sha256-m8l/HpRBJnZ3c0F1u0IyQ3nYGWE0R9V5kfORuqZPzgk=",
|
||||
"owner": "paisano-nix",
|
||||
"repo": "core",
|
||||
"rev": "6674b3d3577212c1eeecd30d62d52edbd000e726",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "paisano-nix",
|
||||
"ref": "0.1.1",
|
||||
"repo": "core",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"paisano-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"paisano-mdbook-preprocessor",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1677306424,
|
||||
"narHash": "sha256-H9/dI2rGEbKo4KEisqbRPHFG2ajF8Tm111NPdKGIf28=",
|
||||
"owner": "paisano-nix",
|
||||
"repo": "actions",
|
||||
"rev": "65ec4e080b3480167fc1a748c89a05901eea9a9b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "paisano-nix",
|
||||
"repo": "actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"paisano-mdbook-preprocessor": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"fenix": "fenix",
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"nixpkgs"
|
||||
],
|
||||
"paisano-actions": "paisano-actions",
|
||||
"std": [
|
||||
"std"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1680654400,
|
||||
"narHash": "sha256-Qdpio+ldhUK3zfl22Mhf8HUULdUOJXDWDdO7MIK69OU=",
|
||||
"owner": "paisano-nix",
|
||||
"repo": "mdbook-paisano-preprocessor",
|
||||
"rev": "11a8fc47f574f194a7ae7b8b98001f6143ba4cf1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "paisano-nix",
|
||||
"repo": "mdbook-paisano-preprocessor",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"paisano-tui": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"blank"
|
||||
],
|
||||
"std": [
|
||||
"std"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681847764,
|
||||
"narHash": "sha256-mdd7PJW1BZvxy0cIKsPfAO+ohVl/V7heE5ZTAHzTdv8=",
|
||||
"owner": "paisano-nix",
|
||||
"repo": "tui",
|
||||
"rev": "3096bad91cae73ab8ab3367d31f8a143d248a244",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "paisano-nix",
|
||||
"ref": "0.1.1",
|
||||
"repo": "tui",
|
||||
"type": "github"
|
||||
"type": "tarball",
|
||||
"url": "https://flakehub.com/f/NixOS/nixpkgs/%2A.tar.gz"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"std": "std"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1677221702,
|
||||
"narHash": "sha256-1M+58rC4eTCWNmmX0hQVZP20t3tfYNunl9D/PrGUyGE=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "f5401f620699b26ed9d47a1d2e838143a18dbe3b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"std",
|
||||
"paisano-mdbook-preprocessor",
|
||||
"crane",
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"paisano-mdbook-preprocessor",
|
||||
"crane",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1675391458,
|
||||
"narHash": "sha256-ukDKZw922BnK5ohL9LhwtaDAdCsJL7L6ScNEyF1lO9w=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "383a4acfd11d778d5c2efcf28376cbd845eeaedf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"std": {
|
||||
"inputs": {
|
||||
"arion": [
|
||||
"std",
|
||||
"blank"
|
||||
],
|
||||
"blank": "blank",
|
||||
"devshell": "devshell",
|
||||
"dmerge": "dmerge",
|
||||
"flake-utils": "flake-utils",
|
||||
"incl": "incl",
|
||||
"makes": [
|
||||
"std",
|
||||
"blank"
|
||||
],
|
||||
"microvm": [
|
||||
"std",
|
||||
"blank"
|
||||
],
|
||||
"n2c": "n2c",
|
||||
"nixago": "nixago",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"paisano": "paisano",
|
||||
"paisano-mdbook-preprocessor": "paisano-mdbook-preprocessor",
|
||||
"paisano-tui": "paisano-tui",
|
||||
"yants": "yants"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1686877329,
|
||||
"narHash": "sha256-A/SU8KqlLP2MBuhi9wmt6gDhXyp+chCeDZ4OBxfSWBI=",
|
||||
"owner": "divnix",
|
||||
"repo": "std",
|
||||
"rev": "aa6d423b82b7b7c2a4545693dea9ed1db14676e7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "divnix",
|
||||
"ref": "v0.23.2",
|
||||
"repo": "std",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"yants": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"std",
|
||||
"dmerge",
|
||||
"nixlib"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1686863218,
|
||||
"narHash": "sha256-kooxYm3/3ornWtVBNHM3Zh020gACUyFX2G0VQXnB+mk=",
|
||||
"owner": "divnix",
|
||||
"repo": "yants",
|
||||
"rev": "8f0da0dba57149676aa4817ec0c880fbde7a648d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "divnix",
|
||||
"repo": "yants",
|
||||
"type": "github"
|
||||
"mfgames-project-setup": "mfgames-project-setup",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
66
flake.nix
66
flake.nix
|
@ -1,26 +1,52 @@
|
|||
{
|
||||
description = "A variety of .NET core libraries used for development";
|
||||
|
||||
inputs = {
|
||||
std.url = "github:divnix/std/v0.23.2";
|
||||
std.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/*.tar.gz";
|
||||
mfgames-project-setup.url = "git+https://src.mfgames.com/nixos-contrib/mfgames-project-setup-flake.git";
|
||||
};
|
||||
|
||||
outputs = inputs @ {
|
||||
self,
|
||||
std,
|
||||
...
|
||||
}:
|
||||
std.growOn {
|
||||
inherit inputs;
|
||||
systems = ["x86_64-linux"];
|
||||
cellsFrom = ./nix;
|
||||
cellBlocks = with std.blockTypes; [
|
||||
(devshells "shells")
|
||||
(nixago "configs")
|
||||
];
|
||||
} {
|
||||
devShells = std.harvest self ["common" "shells"];
|
||||
outputs = inputs @ { self, nixpkgs, mfgames-project-setup, ... }:
|
||||
let
|
||||
# Helpers for producing system-specific outputs
|
||||
supportedSystems = [ "x86_64-linux" ];
|
||||
forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
|
||||
inherit system;
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
});
|
||||
in
|
||||
rec
|
||||
{
|
||||
# Set up the developer shell.
|
||||
devShells = forEachSupportedSystem ({ system, pkgs }:
|
||||
let
|
||||
project-config = mfgames-project-setup.lib.mkConfig {
|
||||
inherit system pkgs;
|
||||
contributorCovenant.enable = true;
|
||||
contributorCovenant.contact = "contact@mfgames.com";
|
||||
developerCertificateOfOrigin.enable = true;
|
||||
dotnet.enable = true;
|
||||
};
|
||||
in
|
||||
{
|
||||
# Shell
|
||||
default = pkgs.mkShell {
|
||||
packages = [
|
||||
pkgs.gnugrep
|
||||
pkgs.gawk
|
||||
pkgs.diffutils
|
||||
pkgs.fd
|
||||
pkgs.just
|
||||
pkgs.lefthook
|
||||
pkgs.jq
|
||||
pkgs.dotnet-sdk
|
||||
pkgs.git
|
||||
]
|
||||
++ project-config.packages;
|
||||
|
||||
shellHook = project-config.shellHook;
|
||||
};
|
||||
});
|
||||
|
||||
# Formatting for the Nix files
|
||||
formatter = forEachSupportedSystem ({ pkgs, ... }: pkgs.nixpkgs-fmt);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,262 +0,0 @@
|
|||
{
|
||||
inputs,
|
||||
cell,
|
||||
}: let
|
||||
inherit (inputs) nixpkgs;
|
||||
inherit (inputs.cells) std presets;
|
||||
l = nixpkgs.lib // builtins;
|
||||
in {
|
||||
conform = {
|
||||
data = {
|
||||
commit = {
|
||||
header = {length = 89;};
|
||||
conventional = {
|
||||
# Only allow these types of conventional commits (inspired by Angular)
|
||||
types = [
|
||||
"build"
|
||||
"chore"
|
||||
"ci"
|
||||
"docs"
|
||||
"feat"
|
||||
"fix"
|
||||
"perf"
|
||||
"refactor"
|
||||
"style"
|
||||
"test"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
editorconfig = {
|
||||
hook.mode = "copy"; # already useful before entering the devshell
|
||||
data = {
|
||||
root = true;
|
||||
|
||||
"*" = {
|
||||
# Common
|
||||
end_of_line = "lf";
|
||||
insert_final_newline = true;
|
||||
trim_trailing_whitespace = true;
|
||||
charset = "utf-8";
|
||||
indent_style = "space";
|
||||
indent_size = 4;
|
||||
indent_brace_style = "K&R";
|
||||
max_line_length = 80;
|
||||
tab_width = 4;
|
||||
curly_bracket_next_line = true;
|
||||
|
||||
# Microsoft .NET properties
|
||||
csharp_new_line_before_members_in_object_initializers = false;
|
||||
csharp_preferred_modifier_order = "public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion";
|
||||
csharp_space_after_cast = false;
|
||||
csharp_style_var_elsewhere = "false:hint";
|
||||
csharp_style_var_for_built_in_types = "false:hint";
|
||||
csharp_style_var_when_type_is_apparent = "true:hint";
|
||||
csharp_preserve_single_line_statements = false;
|
||||
csharp_preserve_single_line_blocks = true;
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = "true:hint";
|
||||
dotnet_style_predefined_type_for_member_access = "true:hint";
|
||||
dotnet_style_qualification_for_event = "true:hint";
|
||||
dotnet_style_qualification_for_field = "true:hint";
|
||||
dotnet_style_qualification_for_method = "true:hint";
|
||||
dotnet_style_qualification_for_property = "true:hint";
|
||||
dotnet_style_require_accessibility_modifiers = "for_non_interface_members:hint";
|
||||
|
||||
# ReSharper properties
|
||||
resharper_alignment_tab_fill_style = "optimal_fill";
|
||||
resharper_apply_on_completion = true;
|
||||
resharper_blank_lines_after_control_transfer_statements = 1;
|
||||
resharper_blank_lines_around_single_line_auto_property = 1;
|
||||
resharper_blank_lines_around_single_line_property = 1;
|
||||
resharper_blank_lines_before_single_line_comment = 1;
|
||||
resharper_blank_lines_between_using_groups = 1;
|
||||
resharper_braces_for_for = "required";
|
||||
resharper_braces_for_foreach = "required";
|
||||
resharper_braces_for_ifelse = "required";
|
||||
resharper_braces_for_while = "required";
|
||||
resharper_can_use_global_alias = false;
|
||||
resharper_csharp_blank_lines_around_single_line_field = 1;
|
||||
resharper_csharp_blank_lines_around_single_line_invocable = 1;
|
||||
resharper_csharp_indent_style = "tab";
|
||||
resharper_csharp_insert_final_newline = true;
|
||||
resharper_csharp_keep_blank_lines_in_code = 1;
|
||||
resharper_csharp_keep_blank_lines_in_declarations = 1;
|
||||
resharper_csharp_new_line_before_while = true;
|
||||
resharper_csharp_use_indent_from_vs = false;
|
||||
resharper_csharp_wrap_arguments_style = "chop_if_long";
|
||||
resharper_csharp_wrap_extends_list_style = "chop_if_long";
|
||||
resharper_csharp_wrap_parameters_style = "chop_if_long";
|
||||
resharper_css_insert_final_newline = false;
|
||||
resharper_enforce_line_ending_style = true;
|
||||
resharper_html_insert_final_newline = false;
|
||||
resharper_indent_nested_fixed_stmt = true;
|
||||
resharper_js_indent_style = "tab";
|
||||
resharper_js_insert_final_newline = true;
|
||||
resharper_js_keep_blank_lines_in_code = 1;
|
||||
resharper_js_stick_comment = false;
|
||||
resharper_js_use_indent_from_vs = false;
|
||||
resharper_js_wrap_before_binary_opsign = true;
|
||||
resharper_js_wrap_chained_method_calls = "chop_if_long";
|
||||
resharper_keep_blank_lines_between_declarations = 1;
|
||||
resharper_min_blank_lines_after_imports = 1;
|
||||
resharper_place_attribute_on_same_line = false;
|
||||
resharper_place_constructor_initializer_on_same_line = false;
|
||||
resharper_place_type_constraints_on_same_line = false;
|
||||
resharper_protobuf_insert_final_newline = false;
|
||||
resharper_qualified_using_at_nested_scope = true;
|
||||
resharper_resx_insert_final_newline = false;
|
||||
resharper_space_within_single_line_array_initializer_braces = true;
|
||||
resharper_use_indents_from_main_language_in_file = false;
|
||||
resharper_vb_insert_final_newline = false;
|
||||
resharper_wrap_after_declaration_lpar = true;
|
||||
resharper_wrap_after_invocation_lpar = true;
|
||||
resharper_wrap_before_extends_colon = true;
|
||||
resharper_wrap_before_first_type_parameter_constraint = true;
|
||||
resharper_wrap_before_type_parameter_langle = true;
|
||||
resharper_xmldoc_indent_child_elements = "ZeroIndent";
|
||||
resharper_xmldoc_indent_text = "ZeroIndent";
|
||||
resharper_xmldoc_insert_final_newline = false;
|
||||
resharper_xml_insert_final_newline = false;
|
||||
|
||||
# ReSharper inspection severities
|
||||
resharper_check_namespace_highlighting = "none";
|
||||
resharper_convert_to_auto_property_highlighting = "none";
|
||||
resharper_localizable_element_highlighting = "none";
|
||||
resharper_redundant_comma_in_attribute_list_highlighting = "none";
|
||||
resharper_redundant_comma_in_enum_declaration_highlighting = "none";
|
||||
resharper_redundant_comma_in_initializer_highlighting = "none";
|
||||
resharper_string_compare_to_is_culture_specific_highlighting = "none";
|
||||
resharper_string_index_of_is_culture_specific_1_highlighting = "none";
|
||||
resharper_use_null_propagation_highlighting = "none";
|
||||
resharper_use_object_or_collection_initializer_highlighting = "hint";
|
||||
resharper_use_string_interpolation_highlighting = "hint";
|
||||
};
|
||||
|
||||
"*.{diff,patch}" = {
|
||||
end_of_line = "unset";
|
||||
insert_final_newline = "unset";
|
||||
trim_trailing_whitespace = "unset";
|
||||
indent_size = "unset";
|
||||
};
|
||||
|
||||
"*.md" = {
|
||||
max_line_length = "off";
|
||||
trim_trailing_whitespace = false;
|
||||
};
|
||||
|
||||
"package.json" = {
|
||||
indent_style = "space";
|
||||
indent_size = 2;
|
||||
tab_width = 2;
|
||||
};
|
||||
|
||||
"*.{appxmanifest,build,config,csproj,dbml,discomap,dtd,jsproj,lsproj,njsproj,nuspec,proj,props,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}" = {
|
||||
indent_style = "space";
|
||||
indent_size = 2;
|
||||
tab_width = 2;
|
||||
};
|
||||
|
||||
"{LICENSES/**,LICENSE}" = {
|
||||
end_of_line = "unset";
|
||||
insert_final_newline = "unset";
|
||||
trim_trailing_whitespace = "unset";
|
||||
charset = "unset";
|
||||
indent_style = "unset";
|
||||
indent_size = "unset";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
lefthook = {
|
||||
data = {
|
||||
commit-msg = {
|
||||
commands = {
|
||||
# Runs conform on commit-msg hook to ensure commit messages are
|
||||
# compliant.
|
||||
conform = {
|
||||
run = "${nixpkgs.conform}/bin/conform enforce --commit-msg-file {1}";
|
||||
};
|
||||
};
|
||||
};
|
||||
pre-commit = {
|
||||
commands = {
|
||||
# Runs treefmt on pre-commit hook to ensure checked-in source code is
|
||||
# properly formatted.
|
||||
treefmt = {
|
||||
run = "${nixpkgs.treefmt}/bin/treefmt {staged_files}";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
prettier = {
|
||||
data = {
|
||||
printWidth = 80;
|
||||
proseWrap = "always";
|
||||
};
|
||||
output = ".prettierrc";
|
||||
format = "json";
|
||||
};
|
||||
|
||||
treefmt = {
|
||||
data = {
|
||||
formatter = {
|
||||
dotnet = {
|
||||
command = "dotnet";
|
||||
options = ["jb" "cleanupcode"];
|
||||
includes = ["*.cs"];
|
||||
};
|
||||
|
||||
nix = {
|
||||
command = "alejandra";
|
||||
includes = ["*.nix" "*.nix.hbs"];
|
||||
};
|
||||
|
||||
prettier = {
|
||||
command = "prettier";
|
||||
# 2023-09-02 DREM: Removed "--plugin" "prettier-plugin-toml"
|
||||
options = ["--write"];
|
||||
includes = [
|
||||
"*.css"
|
||||
"*.html"
|
||||
"*.js"
|
||||
"*.json"
|
||||
"*.jsx"
|
||||
"*.md"
|
||||
"*.mdx"
|
||||
"*.scss"
|
||||
"*.ts"
|
||||
"*.yaml"
|
||||
#"*.toml"
|
||||
];
|
||||
};
|
||||
|
||||
shell = {
|
||||
command = "shfmt";
|
||||
options = ["-i" "4" "-s" "-w"];
|
||||
includes = ["*.sh"];
|
||||
};
|
||||
|
||||
# We mainly use it here to format the Markdown in our README.
|
||||
prettier = {
|
||||
excludes = ["**.min.js"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
packages = [
|
||||
nixpkgs.alejandra
|
||||
nixpkgs.nodePackages.prettier
|
||||
nixpkgs.nodePackages.prettier-plugin-toml
|
||||
nixpkgs.shfmt
|
||||
nixpkgs.go
|
||||
];
|
||||
|
||||
#devshell.startup.prettier-plugin-toml = l.stringsWithDeps.noDepEntry ''
|
||||
# export NODE_PATH=${nixpkgs.nodePackages.prettier-plugin-toml}/lib/node_modules:$NODE_PATH
|
||||
#'';
|
||||
};
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
inputs,
|
||||
cell,
|
||||
}: let
|
||||
inherit (inputs.std) std lib;
|
||||
inherit (inputs) nixpkgs;
|
||||
inherit (inputs.cells) cli;
|
||||
|
||||
l = nixpkgs.lib // builtins;
|
||||
|
||||
dev = lib.dev.mkShell {
|
||||
packages = [
|
||||
# Linux
|
||||
nixpkgs.gnugrep
|
||||
nixpkgs.gawk
|
||||
nixpkgs.diffutils
|
||||
nixpkgs.fd
|
||||
|
||||
# Building
|
||||
nixpkgs.just
|
||||
nixpkgs.lefthook
|
||||
nixpkgs.jq
|
||||
|
||||
# .NET
|
||||
nixpkgs.dotnet-sdk
|
||||
|
||||
# Nix
|
||||
nixpkgs.nixfmt
|
||||
nixpkgs.alejandra
|
||||
|
||||
# Git
|
||||
nixpkgs.git
|
||||
];
|
||||
|
||||
nixago = [
|
||||
(lib.cfg.conform cell.configs.conform)
|
||||
(lib.cfg.treefmt cell.configs.treefmt)
|
||||
(lib.cfg.editorconfig cell.configs.editorconfig)
|
||||
(lib.cfg.lefthook cell.configs.lefthook)
|
||||
];
|
||||
};
|
||||
in {
|
||||
inherit dev;
|
||||
default = dev;
|
||||
}
|
|
@ -2,18 +2,18 @@ namespace MfGames.Crypto;
|
|||
|
||||
public enum ByteStringFormat
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that the format should be lowercase hex characters.
|
||||
/// </summary>
|
||||
LowercaseHex,
|
||||
/// <summary>
|
||||
/// Indicates that the format should be lowercase hex characters.
|
||||
/// </summary>
|
||||
LowercaseHex,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the format should be uppercase hex characters.
|
||||
/// </summary>
|
||||
UppercaseHex,
|
||||
/// <summary>
|
||||
/// Indicates that the format should be uppercase hex characters.
|
||||
/// </summary>
|
||||
UppercaseHex,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the format should be Base64.
|
||||
/// </summary>
|
||||
Base64,
|
||||
/// <summary>
|
||||
/// Indicates that the format should be Base64.
|
||||
/// </summary>
|
||||
Base64,
|
||||
}
|
||||
|
|
|
@ -7,67 +7,62 @@ namespace MfGames.Crypto.Extensions;
|
|||
/// </summary>
|
||||
public static class CryptoByteArrayExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the input into a hash string, such as hex or base64.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="format"></param>
|
||||
/// <returns></returns>
|
||||
public static string? ToByteString(
|
||||
this byte[]? input,
|
||||
ByteStringFormat format = ByteStringFormat.LowercaseHex)
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the input into a hash string, such as hex or base64.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="format"></param>
|
||||
/// <returns></returns>
|
||||
public static string? ToByteString(
|
||||
this byte[]? input,
|
||||
ByteStringFormat format = ByteStringFormat.LowercaseHex
|
||||
)
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case ByteStringFormat.LowercaseHex:
|
||||
return Convert.ToHexString(input).ToLowerInvariant();
|
||||
switch (format)
|
||||
{
|
||||
case ByteStringFormat.LowercaseHex:
|
||||
return Convert.ToHexString(input).ToLowerInvariant();
|
||||
|
||||
case ByteStringFormat.UppercaseHex:
|
||||
return Convert.ToHexString(input);
|
||||
case ByteStringFormat.UppercaseHex:
|
||||
return Convert.ToHexString(input);
|
||||
|
||||
case ByteStringFormat.Base64:
|
||||
return Convert.ToBase64String(input);
|
||||
case ByteStringFormat.Base64:
|
||||
return Convert.ToBase64String(input);
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(format),
|
||||
format,
|
||||
null);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(format), format, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results.
|
||||
/// </summary>
|
||||
/// <param name="input">A byte array or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static byte[]? ToHashBytes(
|
||||
this byte[]? input,
|
||||
HashType hash = HashType.Sha512)
|
||||
{
|
||||
return input == null
|
||||
? null
|
||||
: hash.CreateHash().ComputeHash(input);
|
||||
}
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results.
|
||||
/// </summary>
|
||||
/// <param name="input">A byte array or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static byte[]? ToHashBytes(this byte[]? input, HashType hash = HashType.Sha512)
|
||||
{
|
||||
return input == null ? null : hash.CreateHash().ComputeHash(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results as a string.
|
||||
/// </summary>
|
||||
/// <param name="input">A byte array or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <param name="format">The format of the requested string.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static string? ToHashString(
|
||||
this byte[]? input,
|
||||
HashType hash = HashType.Sha512,
|
||||
ByteStringFormat format = ByteStringFormat.LowercaseHex)
|
||||
{
|
||||
return input?.ToHashBytes(hash)?.ToByteString(format);
|
||||
}
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results as a string.
|
||||
/// </summary>
|
||||
/// <param name="input">A byte array or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <param name="format">The format of the requested string.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static string? ToHashString(
|
||||
this byte[]? input,
|
||||
HashType hash = HashType.Sha512,
|
||||
ByteStringFormat format = ByteStringFormat.LowercaseHex
|
||||
)
|
||||
{
|
||||
return input?.ToHashBytes(hash)?.ToByteString(format);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Text;
|
||||
|
||||
using MfGames.Crypto.Hashes;
|
||||
|
||||
namespace MfGames.Crypto.Extensions;
|
||||
|
@ -9,54 +8,50 @@ namespace MfGames.Crypto.Extensions;
|
|||
/// </summary>
|
||||
public static class CryptoStringExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the encoded byte array of the given string.
|
||||
/// </summary>
|
||||
/// <param name="input">The input string or null.</param>
|
||||
/// <param name="encoding">The encoding to use, defaults to UTF-8.</param>
|
||||
/// <returns>Null if the input was null, otherwise the byte array.</returns>
|
||||
public static byte[]? ToBytes(
|
||||
this string? input,
|
||||
Encoding? encoding = null)
|
||||
{
|
||||
encoding ??= Encoding.UTF8;
|
||||
/// <summary>
|
||||
/// Gets the encoded byte array of the given string.
|
||||
/// </summary>
|
||||
/// <param name="input">The input string or null.</param>
|
||||
/// <param name="encoding">The encoding to use, defaults to UTF-8.</param>
|
||||
/// <returns>Null if the input was null, otherwise the byte array.</returns>
|
||||
public static byte[]? ToBytes(this string? input, Encoding? encoding = null)
|
||||
{
|
||||
encoding ??= Encoding.UTF8;
|
||||
|
||||
return input == null
|
||||
? null
|
||||
: encoding.GetBytes(input);
|
||||
}
|
||||
return input == null ? null : encoding.GetBytes(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results.
|
||||
/// </summary>
|
||||
/// <param name="input">A byte array or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <param name="encoding">The encoding to use, defaults to UTF-8.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static byte[]? ToHashBytes(
|
||||
this string? input,
|
||||
HashType hash = HashType.Sha512,
|
||||
Encoding? encoding = null)
|
||||
{
|
||||
return input == null
|
||||
? null
|
||||
: hash.CreateHash().ComputeHash(input.ToBytes(encoding)!);
|
||||
}
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results.
|
||||
/// </summary>
|
||||
/// <param name="input">A byte array or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <param name="encoding">The encoding to use, defaults to UTF-8.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static byte[]? ToHashBytes(
|
||||
this string? input,
|
||||
HashType hash = HashType.Sha512,
|
||||
Encoding? encoding = null
|
||||
)
|
||||
{
|
||||
return input == null ? null : hash.CreateHash().ComputeHash(input.ToBytes(encoding)!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results as a string.
|
||||
/// </summary>
|
||||
/// <param name="input">A byte array or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <param name="format">The format of the requested string.</param>
|
||||
/// <param name="encoding">The encoding to use, defaults to UTF-8.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static string? ToHashString(
|
||||
this string? input,
|
||||
HashType hash = HashType.Sha512,
|
||||
ByteStringFormat format = ByteStringFormat.LowercaseHex,
|
||||
Encoding? encoding = null)
|
||||
{
|
||||
return input?.ToHashBytes(hash, encoding)?.ToByteString(format);
|
||||
}
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results as a string.
|
||||
/// </summary>
|
||||
/// <param name="input">A byte array or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <param name="format">The format of the requested string.</param>
|
||||
/// <param name="encoding">The encoding to use, defaults to UTF-8.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static string? ToHashString(
|
||||
this string? input,
|
||||
HashType hash = HashType.Sha512,
|
||||
ByteStringFormat format = ByteStringFormat.LowercaseHex,
|
||||
Encoding? encoding = null
|
||||
)
|
||||
{
|
||||
return input?.ToHashBytes(hash, encoding)?.ToByteString(format);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,23 +5,23 @@ namespace MfGames.Crypto.Hashes;
|
|||
/// </summary>
|
||||
public enum HashType
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates a SHA-512 hash.
|
||||
/// </summary>
|
||||
Sha512,
|
||||
/// <summary>
|
||||
/// Indicates a SHA-512 hash.
|
||||
/// </summary>
|
||||
Sha512,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a SHA-256 hash.
|
||||
/// </summary>
|
||||
Sha256,
|
||||
/// <summary>
|
||||
/// Indicates a SHA-256 hash.
|
||||
/// </summary>
|
||||
Sha256,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a SHA-1 hash.
|
||||
/// </summary>
|
||||
Sha1,
|
||||
/// <summary>
|
||||
/// Indicates a SHA-1 hash.
|
||||
/// </summary>
|
||||
Sha1,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a MD5 hash.
|
||||
/// </summary>
|
||||
Md5,
|
||||
/// <summary>
|
||||
/// Indicates a MD5 hash.
|
||||
/// </summary>
|
||||
Md5,
|
||||
}
|
||||
|
|
|
@ -4,30 +4,30 @@ namespace MfGames.Crypto.Hashes;
|
|||
|
||||
public static class HashTypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs a hash of the given type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of hash to create.</param>
|
||||
/// <returns>A hash algorithm of the given type.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static HashAlgorithm CreateHash(this HashType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case HashType.Sha512:
|
||||
return SHA512.Create();
|
||||
/// <summary>
|
||||
/// Constructs a hash of the given type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of hash to create.</param>
|
||||
/// <returns>A hash algorithm of the given type.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static HashAlgorithm CreateHash(this HashType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case HashType.Sha512:
|
||||
return SHA512.Create();
|
||||
|
||||
case HashType.Sha256:
|
||||
return SHA256.Create();
|
||||
case HashType.Sha256:
|
||||
return SHA256.Create();
|
||||
|
||||
case HashType.Sha1:
|
||||
return SHA1.Create();
|
||||
case HashType.Sha1:
|
||||
return SHA1.Create();
|
||||
|
||||
case HashType.Md5:
|
||||
return MD5.Create();
|
||||
case HashType.Md5:
|
||||
return MD5.Create();
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,517 +7,497 @@ namespace MfGames.Gallium;
|
|||
/// </summary>
|
||||
public record Entity
|
||||
{
|
||||
public Entity()
|
||||
: this(Interlocked.Increment(ref nextId))
|
||||
{
|
||||
}
|
||||
public Entity()
|
||||
: this(Interlocked.Increment(ref nextId)) { }
|
||||
|
||||
private Entity(int id)
|
||||
{
|
||||
this.Id = id;
|
||||
this.Components = ImmutableDictionary.Create<Type, object>();
|
||||
}
|
||||
private Entity(int id)
|
||||
{
|
||||
this.Id = id;
|
||||
this.Components = ImmutableDictionary.Create<Type, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the optional formatting for an entity. This is used to
|
||||
/// override the ToString functionality to provide additional information.
|
||||
/// If this is null, then the default "ToString" will be called.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This must be a thread-safe function.
|
||||
/// </remarks>
|
||||
public static Func<Entity, string>? ToStringFormatter { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the optional formatting for an entity. This is used to
|
||||
/// override the ToString functionality to provide additional information.
|
||||
/// If this is null, then the default "ToString" will be called.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This must be a thread-safe function.
|
||||
/// </remarks>
|
||||
public static Func<Entity, string>? ToStringFormatter { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual bool Equals(Entity? other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public virtual bool Equals(Entity? other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.Id == other.Id;
|
||||
}
|
||||
return this.Id == other.Id;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Id.GetHashCode();
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Id.GetHashCode();
|
||||
}
|
||||
|
||||
private ImmutableDictionary<Type, object> Components { get; init; }
|
||||
private ImmutableDictionary<Type, object> Components { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The internal ID to ensure the entities are unique. Since we are not
|
||||
/// worried about serialization or using the identifiers from one call
|
||||
/// to another, we can use a simple interlocked identifier instead of
|
||||
/// a factory or provider method.
|
||||
/// </summary>
|
||||
private static int nextId;
|
||||
/// <summary>
|
||||
/// The internal ID to ensure the entities are unique. Since we are not
|
||||
/// worried about serialization or using the identifiers from one call
|
||||
/// to another, we can use a simple interlocked identifier instead of
|
||||
/// a factory or provider method.
|
||||
/// </summary>
|
||||
private static int nextId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has a specific type of
|
||||
/// component registered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">The component type.</typeparam>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool Has<T1>()
|
||||
{
|
||||
return this.Has(typeof(T1));
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has a specific type of
|
||||
/// component registered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">The component type.</typeparam>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool Has<T1>()
|
||||
{
|
||||
return this.Has(typeof(T1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components of the given types
|
||||
/// registered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <returns>
|
||||
/// True if there are components of the given type exists, otherwise
|
||||
/// false.
|
||||
/// </returns>
|
||||
public bool HasAll<T1, T2>()
|
||||
{
|
||||
return this.HasAll(typeof(T1), typeof(T2));
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components of the given types
|
||||
/// registered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <returns>
|
||||
/// True if there are components of the given type exists, otherwise
|
||||
/// false.
|
||||
/// </returns>
|
||||
public bool HasAll<T1, T2>()
|
||||
{
|
||||
return this.HasAll(typeof(T1), typeof(T2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components of the given types
|
||||
/// registered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <typeparam name="T3">The third component type.</typeparam>
|
||||
/// <returns>
|
||||
/// True if there are components of the given type exists, otherwise
|
||||
/// false.
|
||||
/// </returns>
|
||||
public bool HasAll<T1, T2, T3>()
|
||||
{
|
||||
return this.HasAll(typeof(T1), typeof(T2), typeof(T3));
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components of the given types
|
||||
/// registered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <typeparam name="T3">The third component type.</typeparam>
|
||||
/// <returns>
|
||||
/// True if there are components of the given type exists, otherwise
|
||||
/// false.
|
||||
/// </returns>
|
||||
public bool HasAll<T1, T2, T3>()
|
||||
{
|
||||
return this.HasAll(typeof(T1), typeof(T2), typeof(T3));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components of the given types
|
||||
/// registered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <typeparam name="T3">The third component type.</typeparam>
|
||||
/// <typeparam name="T4">The third component type.</typeparam>
|
||||
/// <returns>
|
||||
/// True if there are components of the given type exists, otherwise
|
||||
/// false.
|
||||
/// </returns>
|
||||
public bool HasAll<T1, T2, T3, T4>()
|
||||
{
|
||||
return this.HasAll(typeof(T1), typeof(T2), typeof(T3), typeof(T4));
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components of the given types
|
||||
/// registered.
|
||||
/// </summary>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <typeparam name="T3">The third component type.</typeparam>
|
||||
/// <typeparam name="T4">The third component type.</typeparam>
|
||||
/// <returns>
|
||||
/// True if there are components of the given type exists, otherwise
|
||||
/// false.
|
||||
/// </returns>
|
||||
public bool HasAll<T1, T2, T3, T4>()
|
||||
{
|
||||
return this.HasAll(typeof(T1), typeof(T2), typeof(T3), typeof(T4));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has a specific type of
|
||||
/// component registered.
|
||||
/// </summary>
|
||||
/// <param name="type">The component type.</param>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool Has(Type type)
|
||||
{
|
||||
return this.Components.ContainsKey(type);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has a specific type of
|
||||
/// component registered.
|
||||
/// </summary>
|
||||
/// <param name="type">The component type.</param>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool Has(Type type)
|
||||
{
|
||||
return this.Components.ContainsKey(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components for all the given
|
||||
/// types.
|
||||
/// </summary>
|
||||
/// <param name="t1">The component type.</param>
|
||||
/// <param name="t2">The component type.</param>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool HasAll(
|
||||
Type t1,
|
||||
Type t2)
|
||||
{
|
||||
return this.Has(t1) && this.Components.ContainsKey(t2);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components for all the given
|
||||
/// types.
|
||||
/// </summary>
|
||||
/// <param name="t1">The component type.</param>
|
||||
/// <param name="t2">The component type.</param>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool HasAll(Type t1, Type t2)
|
||||
{
|
||||
return this.Has(t1) && this.Components.ContainsKey(t2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components for all the given
|
||||
/// types.
|
||||
/// </summary>
|
||||
/// <param name="t1">The component type.</param>
|
||||
/// <param name="t2">The component type.</param>
|
||||
/// <param name="t3">The component type.</param>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool HasAll(
|
||||
Type t1,
|
||||
Type t2,
|
||||
Type t3)
|
||||
{
|
||||
return this.HasAll(t1, t2) && this.Components.ContainsKey(t3);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components for all the given
|
||||
/// types.
|
||||
/// </summary>
|
||||
/// <param name="t1">The component type.</param>
|
||||
/// <param name="t2">The component type.</param>
|
||||
/// <param name="t3">The component type.</param>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool HasAll(Type t1, Type t2, Type t3)
|
||||
{
|
||||
return this.HasAll(t1, t2) && this.Components.ContainsKey(t3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components for all the given
|
||||
/// types.
|
||||
/// </summary>
|
||||
/// <param name="t1">The component type.</param>
|
||||
/// <param name="t2">The component type.</param>
|
||||
/// <param name="t3">The component type.</param>
|
||||
/// <param name="t4">The component type.</param>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool HasAll(
|
||||
Type t1,
|
||||
Type t2,
|
||||
Type t3,
|
||||
Type t4)
|
||||
{
|
||||
return this.HasAll(t1, t2, t3) && this.Components.ContainsKey(t4);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the entity has components for all the given
|
||||
/// types.
|
||||
/// </summary>
|
||||
/// <param name="t1">The component type.</param>
|
||||
/// <param name="t2">The component type.</param>
|
||||
/// <param name="t3">The component type.</param>
|
||||
/// <param name="t4">The component type.</param>
|
||||
/// <returns>True if the type exists, otherwise false.</returns>
|
||||
public bool HasAll(Type t1, Type t2, Type t3, Type t4)
|
||||
{
|
||||
return this.HasAll(t1, t2, t3) && this.Components.ContainsKey(t4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a registered component of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The component type.</typeparam>
|
||||
/// <returns>The registered object.</returns>
|
||||
public TType Get<TType>()
|
||||
{
|
||||
return (TType)this.Components[typeof(TType)];
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a registered component of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The component type.</typeparam>
|
||||
/// <returns>The registered object.</returns>
|
||||
public TType Get<TType>()
|
||||
{
|
||||
return (TType)this.Components[typeof(TType)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a registered component of the given type and casts it to
|
||||
/// TType.
|
||||
/// </summary>
|
||||
/// <param name="type">The component key.</param>
|
||||
/// <typeparam name="TType">The component type.</typeparam>
|
||||
/// <returns>The registered object.</returns>
|
||||
public TType Get<TType>(Type type)
|
||||
{
|
||||
return (TType)this.Components[type];
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a registered component of the given type and casts it to
|
||||
/// TType.
|
||||
/// </summary>
|
||||
/// <param name="type">The component key.</param>
|
||||
/// <typeparam name="TType">The component type.</typeparam>
|
||||
/// <returns>The registered object.</returns>
|
||||
public TType Get<TType>(Type type)
|
||||
{
|
||||
return (TType)this.Components[type];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of components registered in the entity.
|
||||
/// </summary>
|
||||
public int Count => this.Components.Count;
|
||||
/// <summary>
|
||||
/// Gets the number of components registered in the entity.
|
||||
/// </summary>
|
||||
public int Count => this.Components.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the given component type if inside the entity, otherwise the
|
||||
/// default value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The component type.</typeparam>
|
||||
/// <returns>The found component or default (typically null).</returns>
|
||||
public TType? GetOptional<TType>()
|
||||
{
|
||||
return this.Has<TType>() ? this.Get<TType>() : default;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the given component type if inside the entity, otherwise the
|
||||
/// default value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The component type.</typeparam>
|
||||
/// <returns>The found component or default (typically null).</returns>
|
||||
public TType? GetOptional<TType>()
|
||||
{
|
||||
return this.Has<TType>() ? this.Get<TType>() : default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to get the value, if present. If not, this returns false
|
||||
/// and the value is undefined. Otherwise, this method returns true
|
||||
/// and the actual value inside that variable.
|
||||
/// </summary>
|
||||
/// <param name="value">The value if contained in the entity.</param>
|
||||
/// <typeparam name="T1">The component type.</typeparam>
|
||||
/// <returns>True if found, otherwise false.</returns>
|
||||
public bool TryGet<T1>(out T1 value)
|
||||
{
|
||||
if (this.Has<T1>())
|
||||
{
|
||||
value = this.Get<T1>();
|
||||
/// <summary>
|
||||
/// Attempts to get the value, if present. If not, this returns false
|
||||
/// and the value is undefined. Otherwise, this method returns true
|
||||
/// and the actual value inside that variable.
|
||||
/// </summary>
|
||||
/// <param name="value">The value if contained in the entity.</param>
|
||||
/// <typeparam name="T1">The component type.</typeparam>
|
||||
/// <returns>True if found, otherwise false.</returns>
|
||||
public bool TryGet<T1>(out T1 value)
|
||||
{
|
||||
if (this.Has<T1>())
|
||||
{
|
||||
value = this.Get<T1>();
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default!;
|
||||
value = default!;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to get the values, if present. If not, this returns false
|
||||
/// and the value is undefined. Otherwise, this method returns true
|
||||
/// and the actual value inside that variable.
|
||||
/// </summary>
|
||||
/// <param name="value1">The value if contained in the entity.</param>
|
||||
/// <param name="value2">The value if contained in the entity.</param>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <returns>True if found, otherwise false.</returns>
|
||||
public bool TryGet<T1, T2>(
|
||||
out T1 value1,
|
||||
out T2 value2)
|
||||
{
|
||||
if (this.HasAll<T1, T2>())
|
||||
{
|
||||
value1 = this.Get<T1>();
|
||||
value2 = this.Get<T2>();
|
||||
/// <summary>
|
||||
/// Attempts to get the values, if present. If not, this returns false
|
||||
/// and the value is undefined. Otherwise, this method returns true
|
||||
/// and the actual value inside that variable.
|
||||
/// </summary>
|
||||
/// <param name="value1">The value if contained in the entity.</param>
|
||||
/// <param name="value2">The value if contained in the entity.</param>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <returns>True if found, otherwise false.</returns>
|
||||
public bool TryGet<T1, T2>(out T1 value1, out T2 value2)
|
||||
{
|
||||
if (this.HasAll<T1, T2>())
|
||||
{
|
||||
value1 = this.Get<T1>();
|
||||
value2 = this.Get<T2>();
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
value1 = default!;
|
||||
value2 = default!;
|
||||
value1 = default!;
|
||||
value2 = default!;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to get the values, if present. If not, this returns false
|
||||
/// and the value is undefined. Otherwise, this method returns true
|
||||
/// and the actual value inside that variable.
|
||||
/// </summary>
|
||||
/// <param name="value1">The value if contained in the entity.</param>
|
||||
/// <param name="value2">The value if contained in the entity.</param>
|
||||
/// <param name="value3">The value if contained in the entity.</param>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <typeparam name="T3">The third component type.</typeparam>
|
||||
/// <returns>True if found, otherwise false.</returns>
|
||||
public bool TryGet<T1, T2, T3>(
|
||||
out T1 value1,
|
||||
out T2 value2,
|
||||
out T3 value3)
|
||||
{
|
||||
if (this.HasAll<T1, T2, T3>())
|
||||
{
|
||||
value1 = this.Get<T1>();
|
||||
value2 = this.Get<T2>();
|
||||
value3 = this.Get<T3>();
|
||||
/// <summary>
|
||||
/// Attempts to get the values, if present. If not, this returns false
|
||||
/// and the value is undefined. Otherwise, this method returns true
|
||||
/// and the actual value inside that variable.
|
||||
/// </summary>
|
||||
/// <param name="value1">The value if contained in the entity.</param>
|
||||
/// <param name="value2">The value if contained in the entity.</param>
|
||||
/// <param name="value3">The value if contained in the entity.</param>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <typeparam name="T3">The third component type.</typeparam>
|
||||
/// <returns>True if found, otherwise false.</returns>
|
||||
public bool TryGet<T1, T2, T3>(out T1 value1, out T2 value2, out T3 value3)
|
||||
{
|
||||
if (this.HasAll<T1, T2, T3>())
|
||||
{
|
||||
value1 = this.Get<T1>();
|
||||
value2 = this.Get<T2>();
|
||||
value3 = this.Get<T3>();
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
value1 = default!;
|
||||
value2 = default!;
|
||||
value3 = default!;
|
||||
value1 = default!;
|
||||
value2 = default!;
|
||||
value3 = default!;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to get the values, if present. If not, this returns false
|
||||
/// and the value is undefined. Otherwise, this method returns true
|
||||
/// and the actual value inside that variable.
|
||||
/// </summary>
|
||||
/// <param name="value1">The value if contained in the entity.</param>
|
||||
/// <param name="value2">The value if contained in the entity.</param>
|
||||
/// <param name="value3">The value if contained in the entity.</param>
|
||||
/// <param name="value4">The value if contained in the entity.</param>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <typeparam name="T3">The third component type.</typeparam>
|
||||
/// <typeparam name="T4">The fourth component type.</typeparam>
|
||||
/// <returns>True if found, otherwise false.</returns>
|
||||
public bool TryGet<T1, T2, T3, T4>(
|
||||
out T1 value1,
|
||||
out T2 value2,
|
||||
out T3 value3,
|
||||
out T4 value4)
|
||||
{
|
||||
if (this.HasAll<T1, T2, T3, T4>())
|
||||
{
|
||||
value1 = this.Get<T1>();
|
||||
value2 = this.Get<T2>();
|
||||
value3 = this.Get<T3>();
|
||||
value4 = this.Get<T4>();
|
||||
/// <summary>
|
||||
/// Attempts to get the values, if present. If not, this returns false
|
||||
/// and the value is undefined. Otherwise, this method returns true
|
||||
/// and the actual value inside that variable.
|
||||
/// </summary>
|
||||
/// <param name="value1">The value if contained in the entity.</param>
|
||||
/// <param name="value2">The value if contained in the entity.</param>
|
||||
/// <param name="value3">The value if contained in the entity.</param>
|
||||
/// <param name="value4">The value if contained in the entity.</param>
|
||||
/// <typeparam name="T1">The first component type.</typeparam>
|
||||
/// <typeparam name="T2">The second component type.</typeparam>
|
||||
/// <typeparam name="T3">The third component type.</typeparam>
|
||||
/// <typeparam name="T4">The fourth component type.</typeparam>
|
||||
/// <returns>True if found, otherwise false.</returns>
|
||||
public bool TryGet<T1, T2, T3, T4>(out T1 value1, out T2 value2, out T3 value3, out T4 value4)
|
||||
{
|
||||
if (this.HasAll<T1, T2, T3, T4>())
|
||||
{
|
||||
value1 = this.Get<T1>();
|
||||
value2 = this.Get<T2>();
|
||||
value3 = this.Get<T3>();
|
||||
value4 = this.Get<T4>();
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
value1 = default!;
|
||||
value2 = default!;
|
||||
value3 = default!;
|
||||
value4 = default!;
|
||||
value1 = default!;
|
||||
value2 = default!;
|
||||
value3 = default!;
|
||||
value4 = default!;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the component in the entity, regardless if there was a
|
||||
/// component already registered.
|
||||
/// </summary>
|
||||
/// <param name="component">The component to register.</param>
|
||||
/// <typeparam name="T1">The component type.</typeparam>
|
||||
/// <returns>The entity for chaining.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public Entity Set<T1>(T1 component)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(component));
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the component in the entity, regardless if there was a
|
||||
/// component already registered.
|
||||
/// </summary>
|
||||
/// <param name="component">The component to register.</param>
|
||||
/// <typeparam name="T1">The component type.</typeparam>
|
||||
/// <returns>The entity for chaining.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public Entity Set<T1>(T1 component)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(component));
|
||||
}
|
||||
|
||||
if (this.Components.TryGetValue(typeof(T1), out object? value)
|
||||
&& value is T1
|
||||
&& value.Equals(component))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (
|
||||
this.Components.TryGetValue(typeof(T1), out object? value)
|
||||
&& value is T1
|
||||
&& value.Equals(component)
|
||||
)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return this with
|
||||
{
|
||||
Components = this.Components.SetItem(typeof(T1), component),
|
||||
};
|
||||
}
|
||||
return this with
|
||||
{
|
||||
Components = this.Components.SetItem(typeof(T1), component),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets zero or more components into an entity in a single call. This does
|
||||
/// not allow for specifying the data type; each item will be added with
|
||||
/// the result of `component.GetType()`.
|
||||
/// </summary>
|
||||
/// <param name="components">
|
||||
/// The components to add to the entity. Any null objects
|
||||
/// will be ignored.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new Entity with the modified component collection if there is at
|
||||
/// least one component to set, otherwise the same entity.
|
||||
/// </returns>
|
||||
public Entity SetAll(params object?[] components)
|
||||
{
|
||||
if (components.Length == 0)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets zero or more components into an entity in a single call. This does
|
||||
/// not allow for specifying the data type; each item will be added with
|
||||
/// the result of `component.GetType()`.
|
||||
/// </summary>
|
||||
/// <param name="components">
|
||||
/// The components to add to the entity. Any null objects
|
||||
/// will be ignored.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new Entity with the modified component collection if there is at
|
||||
/// least one component to set, otherwise the same entity.
|
||||
/// </returns>
|
||||
public Entity SetAll(params object?[] components)
|
||||
{
|
||||
if (components.Length == 0)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
ImmutableDictionary<Type, object> collection = this.Components;
|
||||
ImmutableDictionary<Type, object> collection = this.Components;
|
||||
|
||||
foreach (object? component in components)
|
||||
{
|
||||
if (component != null)
|
||||
{
|
||||
collection = collection.SetItem(component.GetType(), component);
|
||||
}
|
||||
}
|
||||
foreach (object? component in components)
|
||||
{
|
||||
if (component != null)
|
||||
{
|
||||
collection = collection.SetItem(component.GetType(), component);
|
||||
}
|
||||
}
|
||||
|
||||
return this with
|
||||
{
|
||||
Components = collection,
|
||||
};
|
||||
}
|
||||
return this with
|
||||
{
|
||||
Components = collection,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a component to the entity.
|
||||
/// </summary>
|
||||
/// <param name="component">The component to register.</param>
|
||||
/// <typeparam name="T1">The component type.</typeparam>
|
||||
/// <returns>
|
||||
/// The same entity if the component is already registered, otherwise a
|
||||
/// cloned entity with the new component.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public Entity Add<T1>(T1 component)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(component));
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a component to the entity.
|
||||
/// </summary>
|
||||
/// <param name="component">The component to register.</param>
|
||||
/// <typeparam name="T1">The component type.</typeparam>
|
||||
/// <returns>
|
||||
/// The same entity if the component is already registered, otherwise a
|
||||
/// cloned entity with the new component.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public Entity Add<T1>(T1 component)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(component));
|
||||
}
|
||||
|
||||
if (this.Has<T1>())
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"An element with the same type ("
|
||||
+ typeof(T1).FullName
|
||||
+ ") already exists.",
|
||||
nameof(component));
|
||||
}
|
||||
if (this.Has<T1>())
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"An element with the same type (" + typeof(T1).FullName + ") already exists.",
|
||||
nameof(component)
|
||||
);
|
||||
}
|
||||
|
||||
if (this.Components.TryGetValue(typeof(T1), out object? value)
|
||||
&& value is T1
|
||||
&& value.Equals(component))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if (
|
||||
this.Components.TryGetValue(typeof(T1), out object? value)
|
||||
&& value is T1
|
||||
&& value.Equals(component)
|
||||
)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return this with
|
||||
{
|
||||
Components = this.Components.Add(typeof(T1), component)
|
||||
};
|
||||
}
|
||||
return this with
|
||||
{
|
||||
Components = this.Components.Add(typeof(T1), component)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a component to the entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The component type.</typeparam>
|
||||
/// <returns>
|
||||
/// The same entity if the component is already removed, otherwise a
|
||||
/// cloned entity without the new component.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public Entity Remove<TType>()
|
||||
{
|
||||
return this.Remove(typeof(TType));
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes a component to the entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The component type.</typeparam>
|
||||
/// <returns>
|
||||
/// The same entity if the component is already removed, otherwise a
|
||||
/// cloned entity without the new component.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public Entity Remove<TType>()
|
||||
{
|
||||
return this.Remove(typeof(TType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a component to the entity.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The same entity if the component is already removed, otherwise a
|
||||
/// cloned entity without the new component.
|
||||
/// </returns>
|
||||
/// <param name="type">The component type to remove.</param>
|
||||
public Entity Remove(Type type)
|
||||
{
|
||||
if (!this.Has(type))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes a component to the entity.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The same entity if the component is already removed, otherwise a
|
||||
/// cloned entity without the new component.
|
||||
/// </returns>
|
||||
/// <param name="type">The component type to remove.</param>
|
||||
public Entity Remove(Type type)
|
||||
{
|
||||
if (!this.Has(type))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return this with
|
||||
{
|
||||
Components = this.Components.Remove(type)
|
||||
};
|
||||
}
|
||||
return this with
|
||||
{
|
||||
Components = this.Components.Remove(type)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the identifier of the entity. This should be treated as an
|
||||
/// opaque field.
|
||||
/// </summary>
|
||||
public int Id { get; private init; }
|
||||
/// <summary>
|
||||
/// Gets the identifier of the entity. This should be treated as an
|
||||
/// opaque field.
|
||||
/// </summary>
|
||||
public int Id { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of the entity, including copying the identifier.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Entity ExactCopy()
|
||||
{
|
||||
return this with { };
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a copy of the entity, including copying the identifier.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Entity ExactCopy()
|
||||
{
|
||||
return this with { };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of the entity, including components, but with a new
|
||||
/// identifier.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Entity Copy()
|
||||
{
|
||||
return this with
|
||||
{
|
||||
Id = Interlocked.Increment(ref nextId)
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a copy of the entity, including components, but with a new
|
||||
/// identifier.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Entity Copy()
|
||||
{
|
||||
return this with { Id = Interlocked.Increment(ref nextId) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a list of the component types currently registered in the
|
||||
/// Entity.
|
||||
/// </summary>
|
||||
/// <returns>An enumerable of the various component keys.</returns>
|
||||
public IEnumerable<Type> GetComponentTypes()
|
||||
{
|
||||
return this.Components.Keys;
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a list of the component types currently registered in the
|
||||
/// Entity.
|
||||
/// </summary>
|
||||
/// <returns>An enumerable of the various component keys.</returns>
|
||||
public IEnumerable<Type> GetComponentTypes()
|
||||
{
|
||||
return this.Components.Keys;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return ToStringFormatter == null
|
||||
? $"Entity {this.Id} (Components {this.Components.Count:N0})"
|
||||
: ToStringFormatter(this);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return ToStringFormatter == null
|
||||
? $"Entity {this.Id} (Components {this.Components.Count:N0})"
|
||||
: ToStringFormatter(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,23 +2,24 @@ namespace MfGames.Gallium;
|
|||
|
||||
public static class JoinEntityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Merges two sets of entities using the identifier to determine which
|
||||
/// entities are the same. The `merge` function takes both of the
|
||||
/// entities with the Entity from the `input` first and the one from
|
||||
/// `other` second. The returning entity is put into the collection. If
|
||||
/// an entity from the input is not found in other, then it is just
|
||||
/// passed on.
|
||||
/// </summary>
|
||||
/// <param name="input">The enumerable of entities to merge to.</param>
|
||||
/// <param name="other">The collection of entities to merge from.</param>
|
||||
/// <param name="merge">The callback to merge the two.</param>
|
||||
/// <returns>An sequence of entities, merged and unmerged.</returns>
|
||||
public static IEnumerable<Entity> JoinEntity(
|
||||
this IEnumerable<Entity> input,
|
||||
ICollection<Entity> other,
|
||||
Func<Entity, Entity, Entity> merge)
|
||||
{
|
||||
return input.Join(other, a => a.Id, a => a.Id, merge);
|
||||
}
|
||||
/// <summary>
|
||||
/// Merges two sets of entities using the identifier to determine which
|
||||
/// entities are the same. The `merge` function takes both of the
|
||||
/// entities with the Entity from the `input` first and the one from
|
||||
/// `other` second. The returning entity is put into the collection. If
|
||||
/// an entity from the input is not found in other, then it is just
|
||||
/// passed on.
|
||||
/// </summary>
|
||||
/// <param name="input">The enumerable of entities to merge to.</param>
|
||||
/// <param name="other">The collection of entities to merge from.</param>
|
||||
/// <param name="merge">The callback to merge the two.</param>
|
||||
/// <returns>An sequence of entities, merged and unmerged.</returns>
|
||||
public static IEnumerable<Entity> JoinEntity(
|
||||
this IEnumerable<Entity> input,
|
||||
ICollection<Entity> other,
|
||||
Func<Entity, Entity, Entity> merge
|
||||
)
|
||||
{
|
||||
return input.Join(other, a => a.Id, a => a.Id, merge);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,43 +5,40 @@ namespace MfGames.Gallium;
|
|||
/// </summary>
|
||||
public static class SelectComponentExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a component from an entity and return it. If the entity does not have
|
||||
/// the component, it will be
|
||||
/// filtered out.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process.</param>
|
||||
/// <typeparam name="T1">The component type being searched.</typeparam>
|
||||
/// <returns>A sequence of T1.</returns>
|
||||
public static IEnumerable<T1> SelectComponent<T1>(
|
||||
this IEnumerable<Entity> entities)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
if (entity.TryGet(out T1 v1))
|
||||
{
|
||||
yield return v1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a component from an entity and return it. If the entity does not have
|
||||
/// the component, it will be
|
||||
/// filtered out.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process.</param>
|
||||
/// <typeparam name="T1">The component type being searched.</typeparam>
|
||||
/// <returns>A sequence of T1.</returns>
|
||||
public static IEnumerable<T1> SelectComponent<T1>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
if (entity.TryGet(out T1 v1))
|
||||
{
|
||||
yield return v1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a component from an entity and return it. If the entity does not have
|
||||
/// the component, it will be filtered out.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process.</param>
|
||||
/// <param name="t1">The component type being searched.</param>
|
||||
/// <returns>A sequence of T1.</returns>
|
||||
public static IEnumerable<object> SelectComponent(
|
||||
IEnumerable<Entity> entities,
|
||||
Type t1)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
if (entity.Has(t1))
|
||||
{
|
||||
yield return entity.Get<object>(t1);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a component from an entity and return it. If the entity does not have
|
||||
/// the component, it will be filtered out.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process.</param>
|
||||
/// <param name="t1">The component type being searched.</param>
|
||||
/// <returns>A sequence of T1.</returns>
|
||||
public static IEnumerable<object> SelectComponent(IEnumerable<Entity> entities, Type t1)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
if (entity.Has(t1))
|
||||
{
|
||||
yield return entity.Get<object>(t1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,46 +5,43 @@ namespace MfGames.Gallium;
|
|||
/// </summary>
|
||||
public static class SelectComponentOrDefaultExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a component from an entity and return it. If the entity does not have
|
||||
/// the component, then null will be returned.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process.</param>
|
||||
/// <param name="t1">The component type being searched.</param>
|
||||
/// <returns>A sequence of T1 or nulls.</returns>
|
||||
public static IEnumerable<object?> SelectComponent(
|
||||
IEnumerable<Entity> entities,
|
||||
Type t1)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
if (entity.Has(t1))
|
||||
{
|
||||
yield return entity.Get<object>(t1);
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a component from an entity and return it. If the entity does not have
|
||||
/// the component, then null will be returned.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process.</param>
|
||||
/// <param name="t1">The component type being searched.</param>
|
||||
/// <returns>A sequence of T1 or nulls.</returns>
|
||||
public static IEnumerable<object?> SelectComponent(IEnumerable<Entity> entities, Type t1)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
if (entity.Has(t1))
|
||||
{
|
||||
yield return entity.Get<object>(t1);
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a component from an entity and return it. If the entity does not have
|
||||
/// the component, then the default value will be returned.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process.</param>
|
||||
/// <typeparam name="T1">The component type being searched.</typeparam>
|
||||
/// <returns>A sequence of T1.</returns>
|
||||
public static IEnumerable<T1?> SelectComponentOrDefault<T1>(
|
||||
this IEnumerable<Entity> entities)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
if (entity.TryGet(out T1 v1))
|
||||
{
|
||||
yield return v1;
|
||||
}
|
||||
/// <summary>
|
||||
/// Retrieves a component from an entity and return it. If the entity does not have
|
||||
/// the component, then the default value will be returned.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process.</param>
|
||||
/// <typeparam name="T1">The component type being searched.</typeparam>
|
||||
/// <returns>A sequence of T1.</returns>
|
||||
public static IEnumerable<T1?> SelectComponentOrDefault<T1>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
if (entity.TryGet(out T1 v1))
|
||||
{
|
||||
yield return v1;
|
||||
}
|
||||
|
||||
yield return default;
|
||||
}
|
||||
}
|
||||
yield return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,276 +2,279 @@ namespace MfGames.Gallium;
|
|||
|
||||
public static class SelectEntityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, then entities without all the components are included. Otherwise, they
|
||||
/// are excluded.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, Entity?> selectWithComponents,
|
||||
bool includeEntitiesWithoutComponents = true)
|
||||
{
|
||||
return entities.SelectEntity(
|
||||
selectWithComponents,
|
||||
includeEntitiesWithoutComponents ? a => a : a => null);
|
||||
}
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, then entities without all the components are included. Otherwise, they
|
||||
/// are excluded.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, Entity?> selectWithComponents,
|
||||
bool includeEntitiesWithoutComponents = true
|
||||
)
|
||||
{
|
||||
return entities.SelectEntity(
|
||||
selectWithComponents,
|
||||
includeEntitiesWithoutComponents ? a => a : a => null
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, then entities without all the components are included. Otherwise, they
|
||||
/// are excluded.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, Entity?> selectWithComponents,
|
||||
bool includeEntitiesWithoutComponents = true)
|
||||
{
|
||||
return entities.SelectEntity(
|
||||
selectWithComponents,
|
||||
includeEntitiesWithoutComponents ? a => a : a => null);
|
||||
}
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, then entities without all the components are included. Otherwise, they
|
||||
/// are excluded.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, Entity?> selectWithComponents,
|
||||
bool includeEntitiesWithoutComponents = true
|
||||
)
|
||||
{
|
||||
return entities.SelectEntity(
|
||||
selectWithComponents,
|
||||
includeEntitiesWithoutComponents ? a => a : a => null
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, then entities without all the components are included. Otherwise, they
|
||||
/// are excluded.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the third component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, Entity?> selectWithComponents,
|
||||
bool includeEntitiesWithoutComponents = true)
|
||||
{
|
||||
return entities.SelectEntity(
|
||||
selectWithComponents,
|
||||
includeEntitiesWithoutComponents ? a => a : a => null);
|
||||
}
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, then entities without all the components are included. Otherwise, they
|
||||
/// are excluded.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the third component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, Entity?> selectWithComponents,
|
||||
bool includeEntitiesWithoutComponents = true
|
||||
)
|
||||
{
|
||||
return entities.SelectEntity(
|
||||
selectWithComponents,
|
||||
includeEntitiesWithoutComponents ? a => a : a => null
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, then entities without all the components are included. Otherwise, they
|
||||
/// are excluded.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the third component.</typeparam>
|
||||
/// <typeparam name="T4">The type of the fourth component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, T4, Entity?> selectWithComponents,
|
||||
bool includeEntitiesWithoutComponents = true)
|
||||
{
|
||||
return entities.SelectEntity(
|
||||
selectWithComponents,
|
||||
includeEntitiesWithoutComponents ? a => a : a => null);
|
||||
}
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, then entities without all the components are included. Otherwise, they
|
||||
/// are excluded.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the third component.</typeparam>
|
||||
/// <typeparam name="T4">The type of the fourth component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, T4, Entity?> selectWithComponents,
|
||||
bool includeEntitiesWithoutComponents = true
|
||||
)
|
||||
{
|
||||
return entities.SelectEntity(
|
||||
selectWithComponents,
|
||||
includeEntitiesWithoutComponents ? a => a : a => null
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="selectWithoutComponents">
|
||||
/// The optional transformation function for entities that do not have all the
|
||||
/// components. If returns null,
|
||||
/// then the entity will not be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, Entity?> selectWithComponents,
|
||||
Func<Entity, Entity?> selectWithoutComponents)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
Entity? result = entity.TryGet(out T1 value1)
|
||||
? selectWithComponents?.Invoke(entity, value1)
|
||||
: selectWithoutComponents?.Invoke(entity);
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="selectWithoutComponents">
|
||||
/// The optional transformation function for entities that do not have all the
|
||||
/// components. If returns null,
|
||||
/// then the entity will not be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, Entity?> selectWithComponents,
|
||||
Func<Entity, Entity?> selectWithoutComponents
|
||||
)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
Entity? result = entity.TryGet(out T1 value1)
|
||||
? selectWithComponents?.Invoke(entity, value1)
|
||||
: selectWithoutComponents?.Invoke(entity);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result != null)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="selectWithoutComponents">
|
||||
/// The optional transformation function for entities that do not have all the
|
||||
/// components. If returns null,
|
||||
/// then the entity will not be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, Entity?> selectWithComponents,
|
||||
Func<Entity, Entity?> selectWithoutComponents)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
Entity? result = entity.TryGet(out T1 value1)
|
||||
&& entity.TryGet(out T2 value2)
|
||||
? selectWithComponents?.Invoke(entity, value1, value2)
|
||||
: selectWithoutComponents?.Invoke(entity);
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="selectWithoutComponents">
|
||||
/// The optional transformation function for entities that do not have all the
|
||||
/// components. If returns null,
|
||||
/// then the entity will not be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, Entity?> selectWithComponents,
|
||||
Func<Entity, Entity?> selectWithoutComponents
|
||||
)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
Entity? result =
|
||||
entity.TryGet(out T1 value1) && entity.TryGet(out T2 value2)
|
||||
? selectWithComponents?.Invoke(entity, value1, value2)
|
||||
: selectWithoutComponents?.Invoke(entity);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result != null)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="selectWithoutComponents">
|
||||
/// The optional transformation function for entities that do not have all the
|
||||
/// components. If returns null,
|
||||
/// then the entity will not be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the third component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, Entity?> selectWithComponents,
|
||||
Func<Entity, Entity?> selectWithoutComponents)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
Entity? result =
|
||||
entity.TryGet(out T1 value1)
|
||||
&& entity.TryGet(out T2 value2)
|
||||
&& entity.TryGet(out T3 value3)
|
||||
? selectWithComponents?.Invoke(
|
||||
entity,
|
||||
value1,
|
||||
value2,
|
||||
value3)
|
||||
: selectWithoutComponents?.Invoke(entity);
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="selectWithoutComponents">
|
||||
/// The optional transformation function for entities that do not have all the
|
||||
/// components. If returns null,
|
||||
/// then the entity will not be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the third component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, Entity?> selectWithComponents,
|
||||
Func<Entity, Entity?> selectWithoutComponents
|
||||
)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
Entity? result =
|
||||
entity.TryGet(out T1 value1)
|
||||
&& entity.TryGet(out T2 value2)
|
||||
&& entity.TryGet(out T3 value3)
|
||||
? selectWithComponents?.Invoke(entity, value1, value2, value3)
|
||||
: selectWithoutComponents?.Invoke(entity);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result != null)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="selectWithoutComponents">
|
||||
/// The optional transformation function for entities that do not have all the
|
||||
/// components. If returns null,
|
||||
/// then the entity will not be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the third component.</typeparam>
|
||||
/// <typeparam name="T4">The type of the third component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, T4, Entity?> selectWithComponents,
|
||||
Func<Entity, Entity?> selectWithoutComponents)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
Entity? result =
|
||||
entity.TryGet(out T1 value1)
|
||||
&& entity.TryGet(out T2 value2)
|
||||
&& entity.TryGet(out T3 value3)
|
||||
&& entity.TryGet(out T4 value4)
|
||||
? selectWithComponents?.Invoke(
|
||||
entity,
|
||||
value1,
|
||||
value2,
|
||||
value3,
|
||||
value4)
|
||||
: selectWithoutComponents?.Invoke(entity);
|
||||
/// <summary>
|
||||
/// Selects an entity from the given list, filtering on entities with
|
||||
/// the given components.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to parse.</param>
|
||||
/// <param name="selectWithComponents">
|
||||
/// The transformation function for the entity and selected components. If this
|
||||
/// returns null, then the entity
|
||||
/// will be filtered out.
|
||||
/// </param>
|
||||
/// <param name="selectWithoutComponents">
|
||||
/// The optional transformation function for entities that do not have all the
|
||||
/// components. If returns null,
|
||||
/// then the entity will not be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the third component.</typeparam>
|
||||
/// <typeparam name="T4">The type of the third component.</typeparam>
|
||||
/// <returns>An enumeration of transformed entities.</returns>
|
||||
public static IEnumerable<Entity> SelectEntity<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, T4, Entity?> selectWithComponents,
|
||||
Func<Entity, Entity?> selectWithoutComponents
|
||||
)
|
||||
{
|
||||
foreach (Entity entity in entities)
|
||||
{
|
||||
Entity? result =
|
||||
entity.TryGet(out T1 value1)
|
||||
&& entity.TryGet(out T2 value2)
|
||||
&& entity.TryGet(out T3 value3)
|
||||
&& entity.TryGet(out T4 value4)
|
||||
? selectWithComponents?.Invoke(entity, value1, value2, value3, value4)
|
||||
: selectWithoutComponents?.Invoke(entity);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result != null)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,141 +9,145 @@ namespace MfGames.Gallium;
|
|||
/// </summary>
|
||||
public static class SelectManyEntityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Pulls out all the entities that match the given components into an enumeration,
|
||||
/// passes it into the callback
|
||||
/// function, and then optionally merges the entities that did not match before
|
||||
/// returning.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process</param>
|
||||
/// <param name="selectMany">
|
||||
/// The callback function to manipulate the list of
|
||||
/// entities.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, the include entities
|
||||
/// without components.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <returns>An enumeration of entities.</returns>
|
||||
public static IEnumerable<Entity> SelectManyEntity<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<IEnumerable<Entity>, IEnumerable<Entity>> selectMany,
|
||||
bool includeEntitiesWithoutComponents = true)
|
||||
{
|
||||
SplitEntityEnumerations split = entities.SplitEntity<T1>();
|
||||
IEnumerable<Entity> results = selectMany(split.HasAll);
|
||||
/// <summary>
|
||||
/// Pulls out all the entities that match the given components into an enumeration,
|
||||
/// passes it into the callback
|
||||
/// function, and then optionally merges the entities that did not match before
|
||||
/// returning.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process</param>
|
||||
/// <param name="selectMany">
|
||||
/// The callback function to manipulate the list of
|
||||
/// entities.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, the include entities
|
||||
/// without components.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <returns>An enumeration of entities.</returns>
|
||||
public static IEnumerable<Entity> SelectManyEntity<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<IEnumerable<Entity>, IEnumerable<Entity>> selectMany,
|
||||
bool includeEntitiesWithoutComponents = true
|
||||
)
|
||||
{
|
||||
SplitEntityEnumerations split = entities.SplitEntity<T1>();
|
||||
IEnumerable<Entity> results = selectMany(split.HasAll);
|
||||
|
||||
if (includeEntitiesWithoutComponents)
|
||||
{
|
||||
results = results.Union(split.NotHasAll);
|
||||
}
|
||||
if (includeEntitiesWithoutComponents)
|
||||
{
|
||||
results = results.Union(split.NotHasAll);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pulls out all the entities that match the given components into an enumeration,
|
||||
/// passes it into the callback
|
||||
/// function, and then optionally merges the entities that did not match before
|
||||
/// returning.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process</param>
|
||||
/// <param name="selectMany">
|
||||
/// The callback function to manipulate the list of
|
||||
/// entities.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, the include entities
|
||||
/// without components.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of entities.</returns>
|
||||
public static IEnumerable<Entity> SelectManyEntity<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<IEnumerable<Entity>, IEnumerable<Entity>> selectMany,
|
||||
bool includeEntitiesWithoutComponents = true)
|
||||
{
|
||||
SplitEntityEnumerations split = entities.SplitEntity<T1, T2>();
|
||||
IEnumerable<Entity> results = selectMany(split.HasAll);
|
||||
/// <summary>
|
||||
/// Pulls out all the entities that match the given components into an enumeration,
|
||||
/// passes it into the callback
|
||||
/// function, and then optionally merges the entities that did not match before
|
||||
/// returning.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process</param>
|
||||
/// <param name="selectMany">
|
||||
/// The callback function to manipulate the list of
|
||||
/// entities.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, the include entities
|
||||
/// without components.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of entities.</returns>
|
||||
public static IEnumerable<Entity> SelectManyEntity<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<IEnumerable<Entity>, IEnumerable<Entity>> selectMany,
|
||||
bool includeEntitiesWithoutComponents = true
|
||||
)
|
||||
{
|
||||
SplitEntityEnumerations split = entities.SplitEntity<T1, T2>();
|
||||
IEnumerable<Entity> results = selectMany(split.HasAll);
|
||||
|
||||
if (includeEntitiesWithoutComponents)
|
||||
{
|
||||
results = results.Union(split.NotHasAll);
|
||||
}
|
||||
if (includeEntitiesWithoutComponents)
|
||||
{
|
||||
results = results.Union(split.NotHasAll);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pulls out all the entities that match the given components into an enumeration,
|
||||
/// passes it into the callback
|
||||
/// function, and then optionally merges the entities that did not match before
|
||||
/// returning.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process</param>
|
||||
/// <param name="selectMany">
|
||||
/// The callback function to manipulate the list of
|
||||
/// entities.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, the include entities
|
||||
/// without components.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of entities.</returns>
|
||||
public static IEnumerable<Entity> SelectManyEntity<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<IEnumerable<Entity>, IEnumerable<Entity>> selectMany,
|
||||
bool includeEntitiesWithoutComponents = true)
|
||||
{
|
||||
SplitEntityEnumerations split = entities.SplitEntity<T1, T2, T3>();
|
||||
IEnumerable<Entity> results = selectMany(split.HasAll);
|
||||
/// <summary>
|
||||
/// Pulls out all the entities that match the given components into an enumeration,
|
||||
/// passes it into the callback
|
||||
/// function, and then optionally merges the entities that did not match before
|
||||
/// returning.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process</param>
|
||||
/// <param name="selectMany">
|
||||
/// The callback function to manipulate the list of
|
||||
/// entities.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, the include entities
|
||||
/// without components.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of entities.</returns>
|
||||
public static IEnumerable<Entity> SelectManyEntity<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<IEnumerable<Entity>, IEnumerable<Entity>> selectMany,
|
||||
bool includeEntitiesWithoutComponents = true
|
||||
)
|
||||
{
|
||||
SplitEntityEnumerations split = entities.SplitEntity<T1, T2, T3>();
|
||||
IEnumerable<Entity> results = selectMany(split.HasAll);
|
||||
|
||||
if (includeEntitiesWithoutComponents)
|
||||
{
|
||||
results = results.Union(split.NotHasAll);
|
||||
}
|
||||
if (includeEntitiesWithoutComponents)
|
||||
{
|
||||
results = results.Union(split.NotHasAll);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pulls out all the entities that match the given components into an enumeration,
|
||||
/// passes it into the callback
|
||||
/// function, and then optionally merges the entities that did not match before
|
||||
/// returning.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process</param>
|
||||
/// <param name="selectMany">
|
||||
/// The callback function to manipulate the list of
|
||||
/// entities.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, the include entities
|
||||
/// without components.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T4">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of entities.</returns>
|
||||
public static IEnumerable<Entity> SelectManyEntity<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<IEnumerable<Entity>, IEnumerable<Entity>> selectMany,
|
||||
bool includeEntitiesWithoutComponents = true)
|
||||
{
|
||||
SplitEntityEnumerations split = entities.SplitEntity<T1, T2, T3, T4>();
|
||||
IEnumerable<Entity> results = selectMany(split.HasAll);
|
||||
/// <summary>
|
||||
/// Pulls out all the entities that match the given components into an enumeration,
|
||||
/// passes it into the callback
|
||||
/// function, and then optionally merges the entities that did not match before
|
||||
/// returning.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to process</param>
|
||||
/// <param name="selectMany">
|
||||
/// The callback function to manipulate the list of
|
||||
/// entities.
|
||||
/// </param>
|
||||
/// <param name="includeEntitiesWithoutComponents">
|
||||
/// If true, the include entities
|
||||
/// without components.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">The type of the first component.</typeparam>
|
||||
/// <typeparam name="T2">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T3">The type of the second component.</typeparam>
|
||||
/// <typeparam name="T4">The type of the second component.</typeparam>
|
||||
/// <returns>An enumeration of entities.</returns>
|
||||
public static IEnumerable<Entity> SelectManyEntity<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<IEnumerable<Entity>, IEnumerable<Entity>> selectMany,
|
||||
bool includeEntitiesWithoutComponents = true
|
||||
)
|
||||
{
|
||||
SplitEntityEnumerations split = entities.SplitEntity<T1, T2, T3, T4>();
|
||||
IEnumerable<Entity> results = selectMany(split.HasAll);
|
||||
|
||||
if (includeEntitiesWithoutComponents)
|
||||
{
|
||||
results = results.Union(split.NotHasAll);
|
||||
}
|
||||
if (includeEntitiesWithoutComponents)
|
||||
{
|
||||
results = results.Union(split.NotHasAll);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
namespace MfGames.Gallium;
|
||||
|
||||
public record SplitEntityEnumerations(
|
||||
IEnumerable<Entity> HasAll,
|
||||
IEnumerable<Entity> NotHasAll)
|
||||
public record SplitEntityEnumerations(IEnumerable<Entity> HasAll, IEnumerable<Entity> NotHasAll)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a sequence of all entities that have all the given components.
|
||||
/// </summary>
|
||||
public IEnumerable<Entity> HasAll { get; } = HasAll;
|
||||
/// <summary>
|
||||
/// Gets a sequence of all entities that have all the given components.
|
||||
/// </summary>
|
||||
public IEnumerable<Entity> HasAll { get; } = HasAll;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sequence of all entities that do not have all the given components.
|
||||
/// </summary>
|
||||
public IEnumerable<Entity> NotHasAll { get; } = NotHasAll;
|
||||
/// <summary>
|
||||
/// Gets the sequence of all entities that do not have all the given components.
|
||||
/// </summary>
|
||||
public IEnumerable<Entity> NotHasAll { get; } = NotHasAll;
|
||||
}
|
||||
|
|
|
@ -7,290 +7,259 @@ namespace MfGames.Gallium;
|
|||
/// </summary>
|
||||
public static class SplitEntityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given generic components
|
||||
/// and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">
|
||||
/// A component to require to be in included in the first
|
||||
/// list.
|
||||
/// </typeparam>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity
|
||||
<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, bool>? test = null)
|
||||
{
|
||||
test ??= (
|
||||
e,
|
||||
v1) => true;
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given generic components
|
||||
/// and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">
|
||||
/// A component to require to be in included in the first
|
||||
/// list.
|
||||
/// </typeparam>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, bool>? test = null
|
||||
)
|
||||
{
|
||||
test ??= (e, v1) => true;
|
||||
|
||||
return entities.SplitEntity(
|
||||
typeof(T1),
|
||||
(
|
||||
e,
|
||||
v1) => test(e, (T1)v1));
|
||||
}
|
||||
return entities.SplitEntity(typeof(T1), (e, v1) => test(e, (T1)v1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given generic components
|
||||
/// and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T2">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity
|
||||
<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, bool>? test = null)
|
||||
{
|
||||
test ??= (
|
||||
e,
|
||||
v1,
|
||||
v2) => true;
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given generic components
|
||||
/// and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T2">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, bool>? test = null
|
||||
)
|
||||
{
|
||||
test ??= (e, v1, v2) => true;
|
||||
|
||||
return entities.SplitEntity(
|
||||
typeof(T1),
|
||||
typeof(T2),
|
||||
(
|
||||
e,
|
||||
v1,
|
||||
v2) => test(e, (T1)v1, (T2)v2));
|
||||
}
|
||||
return entities.SplitEntity(typeof(T1), typeof(T2), (e, v1, v2) => test(e, (T1)v1, (T2)v2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given generic components
|
||||
/// and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T2">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T3">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity
|
||||
<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, bool>? test = null)
|
||||
{
|
||||
test ??= (
|
||||
e,
|
||||
v1,
|
||||
v2,
|
||||
v3) => true;
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given generic components
|
||||
/// and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T2">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T3">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, bool>? test = null
|
||||
)
|
||||
{
|
||||
test ??= (e, v1, v2, v3) => true;
|
||||
|
||||
return entities.SplitEntity(
|
||||
typeof(T1),
|
||||
typeof(T2),
|
||||
typeof(T3),
|
||||
(
|
||||
e,
|
||||
v1,
|
||||
v2,
|
||||
v3) => test(e, (T1)v1, (T2)v2, (T3)v3));
|
||||
}
|
||||
return entities.SplitEntity(
|
||||
typeof(T1),
|
||||
typeof(T2),
|
||||
typeof(T3),
|
||||
(e, v1, v2, v3) => test(e, (T1)v1, (T2)v2, (T3)v3)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given generic components
|
||||
/// and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T2">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T3">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T4">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity
|
||||
<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, T4, bool>? test = null)
|
||||
{
|
||||
test ??= (
|
||||
e,
|
||||
v1,
|
||||
v2,
|
||||
v3,
|
||||
v4) => true;
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given generic components
|
||||
/// and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <typeparam name="T1">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T2">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T3">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="T4">
|
||||
/// A component to require to be in included in the first list.
|
||||
/// </typeparam>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, T4, bool>? test = null
|
||||
)
|
||||
{
|
||||
test ??= (e, v1, v2, v3, v4) => true;
|
||||
|
||||
return entities.SplitEntity(
|
||||
typeof(T1),
|
||||
typeof(T2),
|
||||
typeof(T3),
|
||||
typeof(T4),
|
||||
(
|
||||
e,
|
||||
v1,
|
||||
v2,
|
||||
v3,
|
||||
v4) => test(e, (T1)v1, (T2)v2, (T3)v3, (T4)v4));
|
||||
}
|
||||
return entities.SplitEntity(
|
||||
typeof(T1),
|
||||
typeof(T2),
|
||||
typeof(T3),
|
||||
typeof(T4),
|
||||
(e, v1, v2, v3, v4) => test(e, (T1)v1, (T2)v2, (T3)v3, (T4)v4)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given component types and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="t1">The type of a required component.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity(
|
||||
this IEnumerable<Entity> entities,
|
||||
Type t1,
|
||||
Func<Entity, object, bool> test)
|
||||
{
|
||||
return SplitEntity(
|
||||
entities,
|
||||
a => a.Has(t1) && test(a, a.Get<object>(t1)));
|
||||
}
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given component types and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="t1">The type of a required component.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity(
|
||||
this IEnumerable<Entity> entities,
|
||||
Type t1,
|
||||
Func<Entity, object, bool> test
|
||||
)
|
||||
{
|
||||
return SplitEntity(entities, a => a.Has(t1) && test(a, a.Get<object>(t1)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given component types and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="t1">The type of a required component.</param>
|
||||
/// <param name="t2">The type of a required component.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity(
|
||||
this IEnumerable<Entity> entities,
|
||||
Type t1,
|
||||
Type t2,
|
||||
Func<Entity, object, object, bool> test)
|
||||
{
|
||||
return SplitEntity(entities, a => a.HasAll(t1, t2));
|
||||
}
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given component types and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="t1">The type of a required component.</param>
|
||||
/// <param name="t2">The type of a required component.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity(
|
||||
this IEnumerable<Entity> entities,
|
||||
Type t1,
|
||||
Type t2,
|
||||
Func<Entity, object, object, bool> test
|
||||
)
|
||||
{
|
||||
return SplitEntity(entities, a => a.HasAll(t1, t2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given component types and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="t1">The type of a required component.</param>
|
||||
/// <param name="t2">The type of a required component.</param>
|
||||
/// <param name="t3">The type of a required component.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity(
|
||||
this IEnumerable<Entity> entities,
|
||||
Type t1,
|
||||
Type t2,
|
||||
Type t3,
|
||||
Func<Entity, object, object, object, bool> test)
|
||||
{
|
||||
return SplitEntity(entities, a => a.HasAll(t1, t2, t3));
|
||||
}
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given component types and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="t1">The type of a required component.</param>
|
||||
/// <param name="t2">The type of a required component.</param>
|
||||
/// <param name="t3">The type of a required component.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity(
|
||||
this IEnumerable<Entity> entities,
|
||||
Type t1,
|
||||
Type t2,
|
||||
Type t3,
|
||||
Func<Entity, object, object, object, bool> test
|
||||
)
|
||||
{
|
||||
return SplitEntity(entities, a => a.HasAll(t1, t2, t3));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given component types and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="t1">The type of a required component.</param>
|
||||
/// <param name="t2">The type of a required component.</param>
|
||||
/// <param name="t3">The type of a required component.</param>
|
||||
/// <param name="t4">The type of a required component.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity(
|
||||
this IEnumerable<Entity> entities,
|
||||
Type t1,
|
||||
Type t2,
|
||||
Type t3,
|
||||
Type t4,
|
||||
Func<Entity, object, object, object, object, bool> test)
|
||||
{
|
||||
return SplitEntity(
|
||||
entities,
|
||||
a => a.HasAll(t1, t2, t3, t4)
|
||||
&& test(
|
||||
a,
|
||||
a.Get<object>(t1),
|
||||
a.Get<object>(t2),
|
||||
a.Get<object>(t3),
|
||||
a.Get<object>(t4)));
|
||||
}
|
||||
/// <summary>
|
||||
/// Splits the enumeration of entities into two separate enumerations, ones that
|
||||
/// have the given component types and those which do not.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities to split into two lists.</param>
|
||||
/// <param name="t1">The type of a required component.</param>
|
||||
/// <param name="t2">The type of a required component.</param>
|
||||
/// <param name="t3">The type of a required component.</param>
|
||||
/// <param name="t4">The type of a required component.</param>
|
||||
/// <param name="test">
|
||||
/// An additional test function to determine if the entity is
|
||||
/// included in the has list. If null, then entities with all the components will
|
||||
/// be included.
|
||||
/// </param>
|
||||
/// <returns>A pair of enumerations, ones with the components and ones without.</returns>
|
||||
public static SplitEntityEnumerations SplitEntity(
|
||||
this IEnumerable<Entity> entities,
|
||||
Type t1,
|
||||
Type t2,
|
||||
Type t3,
|
||||
Type t4,
|
||||
Func<Entity, object, object, object, object, bool> test
|
||||
)
|
||||
{
|
||||
return SplitEntity(
|
||||
entities,
|
||||
a =>
|
||||
a.HasAll(t1, t2, t3, t4)
|
||||
&& test(
|
||||
a,
|
||||
a.Get<object>(t1),
|
||||
a.Get<object>(t2),
|
||||
a.Get<object>(t3),
|
||||
a.Get<object>(t4)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static SplitEntityEnumerations SplitEntity(
|
||||
IEnumerable<Entity> entities,
|
||||
Func<Entity, bool> keySelector)
|
||||
{
|
||||
if (entities == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(entities));
|
||||
}
|
||||
private static SplitEntityEnumerations SplitEntity(
|
||||
IEnumerable<Entity> entities,
|
||||
Func<Entity, bool> keySelector
|
||||
)
|
||||
{
|
||||
if (entities == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(entities));
|
||||
}
|
||||
|
||||
IEnumerable<IGrouping<bool, Entity>> group = entities
|
||||
.GroupBy(keySelector, a => a)
|
||||
.ToList();
|
||||
IEnumerable<IGrouping<bool, Entity>> group = entities.GroupBy(keySelector, a => a).ToList();
|
||||
|
||||
IEnumerable<Entity>? has = group
|
||||
.Where(a => a.Key)
|
||||
.SelectMany(a => a);
|
||||
IEnumerable<Entity>? has = group.Where(a => a.Key).SelectMany(a => a);
|
||||
|
||||
IEnumerable<Entity>? hasNot = group
|
||||
.Where(a => !a.Key)
|
||||
.SelectMany(a => a);
|
||||
IEnumerable<Entity>? hasNot = group.Where(a => !a.Key).SelectMany(a => a);
|
||||
|
||||
return new SplitEntityEnumerations(has, hasNot);
|
||||
}
|
||||
return new SplitEntityEnumerations(has, hasNot);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,42 +2,40 @@ namespace MfGames.Gallium;
|
|||
|
||||
public static class WhereEntityExtensions
|
||||
{
|
||||
public static IEnumerable<Entity> WhereEntity<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, bool> include)
|
||||
{
|
||||
return entities.Where(x => x.Has<T1>() && include(x, x.Get<T1>()));
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntity<T1>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, bool> include
|
||||
)
|
||||
{
|
||||
return entities.Where(x => x.Has<T1>() && include(x, x.Get<T1>()));
|
||||
}
|
||||
|
||||
public static IEnumerable<Entity> WhereEntity<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, bool> include)
|
||||
{
|
||||
return entities.Where(
|
||||
x => x.HasAll<T1, T2>()
|
||||
&& include(x, x.Get<T1>(), x.Get<T2>()));
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntity<T1, T2>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, bool> include
|
||||
)
|
||||
{
|
||||
return entities.Where(x => x.HasAll<T1, T2>() && include(x, x.Get<T1>(), x.Get<T2>()));
|
||||
}
|
||||
|
||||
public static IEnumerable<Entity> WhereEntity<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, bool> include)
|
||||
{
|
||||
return entities.Where(
|
||||
x => x.HasAll<T1, T2, T3>()
|
||||
&& include(x, x.Get<T1>(), x.Get<T2>(), x.Get<T3>()));
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntity<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, bool> include
|
||||
)
|
||||
{
|
||||
return entities.Where(x =>
|
||||
x.HasAll<T1, T2, T3>() && include(x, x.Get<T1>(), x.Get<T2>(), x.Get<T3>())
|
||||
);
|
||||
}
|
||||
|
||||
public static IEnumerable<Entity> WhereEntity<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, T4, bool> include)
|
||||
{
|
||||
return entities.Where(
|
||||
x => x.HasAll<T1, T2, T3, T4>()
|
||||
&& include(
|
||||
x,
|
||||
x.Get<T1>(),
|
||||
x.Get<T2>(),
|
||||
x.Get<T3>(),
|
||||
x.Get<T4>()));
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntity<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities,
|
||||
Func<Entity, T1, T2, T3, T4, bool> include
|
||||
)
|
||||
{
|
||||
return entities.Where(x =>
|
||||
x.HasAll<T1, T2, T3, T4>()
|
||||
&& include(x, x.Get<T1>(), x.Get<T2>(), x.Get<T3>(), x.Get<T4>())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,27 +2,27 @@ namespace MfGames.Gallium;
|
|||
|
||||
public static class WhereEntityHasExtensions
|
||||
{
|
||||
public static IEnumerable<Entity> WhereEntityHas<T1>(
|
||||
this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => x.Has<T1>());
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntityHas<T1>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => x.Has<T1>());
|
||||
}
|
||||
|
||||
public static IEnumerable<Entity> WhereEntityHasAll
|
||||
<T1, T2>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => x.HasAll<T1, T2>());
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntityHasAll<T1, T2>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => x.HasAll<T1, T2>());
|
||||
}
|
||||
|
||||
public static IEnumerable<Entity> WhereEntityHasAll
|
||||
<T1, T2, T3>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => x.HasAll<T1, T2, T3>());
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntityHasAll<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities
|
||||
)
|
||||
{
|
||||
return entities.Where(x => x.HasAll<T1, T2, T3>());
|
||||
}
|
||||
|
||||
public static IEnumerable<Entity> WhereEntityHasAll
|
||||
<T1, T2, T3, T4>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => x.HasAll<T1, T2, T3, T4>());
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntityHasAll<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities
|
||||
)
|
||||
{
|
||||
return entities.Where(x => x.HasAll<T1, T2, T3, T4>());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,27 +2,29 @@ namespace MfGames.Gallium;
|
|||
|
||||
public static class WhereEntityNotHasExtensions
|
||||
{
|
||||
public static IEnumerable<Entity> WhereEntityNotHas<T1>(
|
||||
this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => !x.Has<T1>());
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntityNotHas<T1>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => !x.Has<T1>());
|
||||
}
|
||||
|
||||
public static IEnumerable<Entity> WhereEntityNotHasAll
|
||||
<T1, T2>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => !x.HasAll<T1, T2>());
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntityNotHasAll<T1, T2>(
|
||||
this IEnumerable<Entity> entities
|
||||
)
|
||||
{
|
||||
return entities.Where(x => !x.HasAll<T1, T2>());
|
||||
}
|
||||
|
||||
public static IEnumerable<Entity> WhereEntityNotHasAll
|
||||
<T1, T2, T3>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => !x.HasAll<T1, T2, T3>());
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntityNotHasAll<T1, T2, T3>(
|
||||
this IEnumerable<Entity> entities
|
||||
)
|
||||
{
|
||||
return entities.Where(x => !x.HasAll<T1, T2, T3>());
|
||||
}
|
||||
|
||||
public static IEnumerable<Entity> WhereEntityNotHasAll
|
||||
<T1, T2, T3, T4>(this IEnumerable<Entity> entities)
|
||||
{
|
||||
return entities.Where(x => !x.HasAll<T1, T2, T3, T4>());
|
||||
}
|
||||
public static IEnumerable<Entity> WhereEntityNotHasAll<T1, T2, T3, T4>(
|
||||
this IEnumerable<Entity> entities
|
||||
)
|
||||
{
|
||||
return entities.Where(x => !x.HasAll<T1, T2, T3, T4>());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,25 +7,23 @@ namespace MfGames.IO.Extensions;
|
|||
/// </summary>
|
||||
public static class AssemblyExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the directory for a given assembly.
|
||||
/// </summary>
|
||||
/// <param name="assembly">The assembly to get the directory.</param>
|
||||
/// <returns>The directory or null if the assembly or location is null.</returns>
|
||||
public static DirectoryInfo? GetDirectory(this Assembly? assembly)
|
||||
{
|
||||
return assembly.GetFile()?.Directory;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the directory for a given assembly.
|
||||
/// </summary>
|
||||
/// <param name="assembly">The assembly to get the directory.</param>
|
||||
/// <returns>The directory or null if the assembly or location is null.</returns>
|
||||
public static DirectoryInfo? GetDirectory(this Assembly? assembly)
|
||||
{
|
||||
return assembly.GetFile()?.Directory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file for a given assembly.
|
||||
/// </summary>
|
||||
/// <param name="assembly">The assembly to get the directory.</param>
|
||||
/// <returns>The directory or null if the assembly or location is null.</returns>
|
||||
public static FileInfo? GetFile(this Assembly? assembly)
|
||||
{
|
||||
return assembly?.Location == null
|
||||
? null
|
||||
: new FileInfo(assembly.Location);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the file for a given assembly.
|
||||
/// </summary>
|
||||
/// <param name="assembly">The assembly to get the directory.</param>
|
||||
/// <returns>The directory or null if the assembly or location is null.</returns>
|
||||
public static FileInfo? GetFile(this Assembly? assembly)
|
||||
{
|
||||
return assembly?.Location == null ? null : new FileInfo(assembly.Location);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,41 +9,37 @@ namespace MfGames.IO.Extensions;
|
|||
/// </summary>
|
||||
public static class CryptoFileInfoExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results.
|
||||
/// </summary>
|
||||
/// <param name="file">The FileInfo object or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static byte[]? ToHashBytes(
|
||||
this FileInfo? file,
|
||||
HashType hash = HashType.Sha512)
|
||||
{
|
||||
if (file == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results.
|
||||
/// </summary>
|
||||
/// <param name="file">The FileInfo object or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static byte[]? ToHashBytes(this FileInfo? file, HashType hash = HashType.Sha512)
|
||||
{
|
||||
if (file == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using FileStream stream = file.Open(
|
||||
FileMode.Open,
|
||||
FileAccess.Read,
|
||||
FileShare.Read);
|
||||
using FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
|
||||
return hash.CreateHash().ComputeHash(stream);
|
||||
}
|
||||
return hash.CreateHash().ComputeHash(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results as a string.
|
||||
/// </summary>
|
||||
/// <param name="file">The FileInfo object or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <param name="format">The format of the requested string.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static string? ToHashString(
|
||||
this FileInfo? file,
|
||||
HashType hash = HashType.Sha512,
|
||||
ByteStringFormat format = ByteStringFormat.LowercaseHex)
|
||||
{
|
||||
return file?.ToHashBytes(hash).ToByteString(format);
|
||||
}
|
||||
/// <summary>
|
||||
/// Hashes the given input and returns the results as a string.
|
||||
/// </summary>
|
||||
/// <param name="file">The FileInfo object or null.</param>
|
||||
/// <param name="hash">The type of hash requested.</param>
|
||||
/// <param name="format">The format of the requested string.</param>
|
||||
/// <returns>Null if input is null, otherwise the hash value.</returns>
|
||||
public static string? ToHashString(
|
||||
this FileInfo? file,
|
||||
HashType hash = HashType.Sha512,
|
||||
ByteStringFormat format = ByteStringFormat.LowercaseHex
|
||||
)
|
||||
{
|
||||
return file?.ToHashBytes(hash).ToByteString(format);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,166 +5,157 @@ namespace MfGames.IO.Extensions;
|
|||
/// </summary>
|
||||
public static class DirectoryInfoExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes sure a directory exists, creating it and any parents above it
|
||||
/// as needed.
|
||||
/// </summary>
|
||||
/// <param name="directory"></param>
|
||||
/// <returns>The directory passed in.</returns>
|
||||
public static DirectoryInfo? CreateIfMissing(this DirectoryInfo? directory)
|
||||
{
|
||||
// Ignore blanks.
|
||||
if (directory == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Makes sure a directory exists, creating it and any parents above it
|
||||
/// as needed.
|
||||
/// </summary>
|
||||
/// <param name="directory"></param>
|
||||
/// <returns>The directory passed in.</returns>
|
||||
public static DirectoryInfo? CreateIfMissing(this DirectoryInfo? directory)
|
||||
{
|
||||
// Ignore blanks.
|
||||
if (directory == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check the parent first. We don't have to worry about null because
|
||||
// we check that coming in.
|
||||
directory.Parent.CreateIfMissing();
|
||||
// Check the parent first. We don't have to worry about null because
|
||||
// we check that coming in.
|
||||
directory.Parent.CreateIfMissing();
|
||||
|
||||
// If the directory doesn't exist, create it.
|
||||
if (!Directory.Exists(directory.FullName))
|
||||
{
|
||||
directory.Create();
|
||||
}
|
||||
// If the directory doesn't exist, create it.
|
||||
if (!Directory.Exists(directory.FullName))
|
||||
{
|
||||
directory.Create();
|
||||
}
|
||||
|
||||
return directory;
|
||||
}
|
||||
return directory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for the Git root starting at the given directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to start searching.</param>
|
||||
/// <returns>The directory containing `.git`, otherwise null.</returns>
|
||||
public static DirectoryInfo? FindGitRoot(this DirectoryInfo? directory)
|
||||
{
|
||||
return directory.FindSelfOrParent(IsGitRoot);
|
||||
}
|
||||
/// <summary>
|
||||
/// Searches for the Git root starting at the given directory.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to start searching.</param>
|
||||
/// <returns>The directory containing `.git`, otherwise null.</returns>
|
||||
public static DirectoryInfo? FindGitRoot(this DirectoryInfo? directory)
|
||||
{
|
||||
return directory.FindSelfOrParent(IsGitRoot);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for a parent that matches the given `match` method. This
|
||||
/// will not compare the given directory to see if it matches.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to start searching.</param>
|
||||
/// <param name="match">The function that takes a directory to determine a match.</param>
|
||||
/// <returns>A parent directory that matches, otherwise null.</returns>
|
||||
public static DirectoryInfo? FindParent(
|
||||
this DirectoryInfo? directory,
|
||||
Func<DirectoryInfo, bool> match)
|
||||
{
|
||||
return directory == null
|
||||
? null
|
||||
: FindSelfOrParent(directory.Parent, match);
|
||||
}
|
||||
/// <summary>
|
||||
/// Searches for a parent that matches the given `match` method. This
|
||||
/// will not compare the given directory to see if it matches.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to start searching.</param>
|
||||
/// <param name="match">The function that takes a directory to determine a match.</param>
|
||||
/// <returns>A parent directory that matches, otherwise null.</returns>
|
||||
public static DirectoryInfo? FindParent(
|
||||
this DirectoryInfo? directory,
|
||||
Func<DirectoryInfo, bool> match
|
||||
)
|
||||
{
|
||||
return directory == null ? null : FindSelfOrParent(directory.Parent, match);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the given directory and parents for the first one that
|
||||
/// matches (moving up the directory tree). If this does not find
|
||||
/// anything, then a null will be returned.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to start searching.</param>
|
||||
/// <param name="match">The function that takes a directory to determine a match.</param>
|
||||
/// <returns>A parent directory that matches, otherwise null.</returns>
|
||||
public static DirectoryInfo? FindSelfOrParent(
|
||||
this DirectoryInfo? directory,
|
||||
Func<DirectoryInfo, bool> match)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Validate our inputs.
|
||||
if (match == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(match));
|
||||
}
|
||||
/// <summary>
|
||||
/// Searches the given directory and parents for the first one that
|
||||
/// matches (moving up the directory tree). If this does not find
|
||||
/// anything, then a null will be returned.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to start searching.</param>
|
||||
/// <param name="match">The function that takes a directory to determine a match.</param>
|
||||
/// <returns>A parent directory that matches, otherwise null.</returns>
|
||||
public static DirectoryInfo? FindSelfOrParent(
|
||||
this DirectoryInfo? directory,
|
||||
Func<DirectoryInfo, bool> match
|
||||
)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Validate our inputs.
|
||||
if (match == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(match));
|
||||
}
|
||||
|
||||
// If the directory is null, just return null. Same with
|
||||
// non-existing directories. We don't use directory.Exists here
|
||||
// because it seems to be cached and we get incorrect data.
|
||||
if (directory == null || !Directory.Exists(directory.FullName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// If the directory is null, just return null. Same with
|
||||
// non-existing directories. We don't use directory.Exists here
|
||||
// because it seems to be cached and we get incorrect data.
|
||||
if (directory == null || !Directory.Exists(directory.FullName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check this directory for a match, otherwise move up.
|
||||
if (match(directory))
|
||||
{
|
||||
return directory;
|
||||
}
|
||||
// Check this directory for a match, otherwise move up.
|
||||
if (match(directory))
|
||||
{
|
||||
return directory;
|
||||
}
|
||||
|
||||
directory = directory.Parent;
|
||||
}
|
||||
}
|
||||
directory = directory.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a DirectoryInfo by combining the path components with the
|
||||
/// directory full path.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to get the root path.</param>
|
||||
/// <param name="paths">Additional child paths.</param>
|
||||
/// <returns>A DirectoryInfo of the given path.</returns>
|
||||
public static DirectoryInfo GetDirectory(
|
||||
this DirectoryInfo directory,
|
||||
params string[] paths)
|
||||
{
|
||||
if (directory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(directory));
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a DirectoryInfo by combining the path components with the
|
||||
/// directory full path.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to get the root path.</param>
|
||||
/// <param name="paths">Additional child paths.</param>
|
||||
/// <returns>A DirectoryInfo of the given path.</returns>
|
||||
public static DirectoryInfo GetDirectory(this DirectoryInfo directory, params string[] paths)
|
||||
{
|
||||
if (directory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(directory));
|
||||
}
|
||||
|
||||
if (paths == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(paths));
|
||||
}
|
||||
if (paths == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(paths));
|
||||
}
|
||||
|
||||
string[] parts = new[] { directory.FullName }
|
||||
.Union(paths)
|
||||
.ToArray();
|
||||
string path = Path.Combine(parts);
|
||||
var info = new DirectoryInfo(path);
|
||||
string[] parts = new[] { directory.FullName }.Union(paths).ToArray();
|
||||
string path = Path.Combine(parts);
|
||||
var info = new DirectoryInfo(path);
|
||||
|
||||
return info;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a FileInfo by combining the path components with the directory
|
||||
/// full path.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to get the root path.</param>
|
||||
/// <param name="paths">Additional child paths.</param>
|
||||
/// <returns>A FileInfo of the given path.</returns>
|
||||
public static FileInfo GetFile(
|
||||
this DirectoryInfo directory,
|
||||
params string[] paths)
|
||||
{
|
||||
if (directory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(directory));
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a FileInfo by combining the path components with the directory
|
||||
/// full path.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to get the root path.</param>
|
||||
/// <param name="paths">Additional child paths.</param>
|
||||
/// <returns>A FileInfo of the given path.</returns>
|
||||
public static FileInfo GetFile(this DirectoryInfo directory, params string[] paths)
|
||||
{
|
||||
if (directory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(directory));
|
||||
}
|
||||
|
||||
if (paths == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(paths));
|
||||
}
|
||||
if (paths == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(paths));
|
||||
}
|
||||
|
||||
string[] parts = new[] { directory.FullName }
|
||||
.Union(paths)
|
||||
.ToArray();
|
||||
string path = Path.Combine(parts);
|
||||
var info = new FileInfo(path);
|
||||
string[] parts = new[] { directory.FullName }.Union(paths).ToArray();
|
||||
string path = Path.Combine(parts);
|
||||
var info = new FileInfo(path);
|
||||
|
||||
return info;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the given directory contains a ".git" folder. If given
|
||||
/// a null, this will always return false.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to inspect.</param>
|
||||
/// <returns>True if the directory contains ".git", otherwise false.</returns>
|
||||
public static bool IsGitRoot(this DirectoryInfo? directory)
|
||||
{
|
||||
return directory != null
|
||||
&& directory.GetDirectories(".git").Length > 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines if the given directory contains a ".git" folder. If given
|
||||
/// a null, this will always return false.
|
||||
/// </summary>
|
||||
/// <param name="directory">The directory to inspect.</param>
|
||||
/// <returns>True if the directory contains ".git", otherwise false.</returns>
|
||||
public static bool IsGitRoot(this DirectoryInfo? directory)
|
||||
{
|
||||
return directory != null && directory.GetDirectories(".git").Length > 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,48 +7,45 @@ namespace MfGames.IO.Extensions;
|
|||
/// </summary>
|
||||
public static class FileInfoExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads all the text from a FileInfo object.
|
||||
/// </summary>
|
||||
/// <param name="file">The file to read from.</param>
|
||||
/// <returns>The text contents.</returns>
|
||||
public static string ReadAllText(this FileInfo file)
|
||||
{
|
||||
return File.ReadAllText(file.FullName);
|
||||
}
|
||||
/// <summary>
|
||||
/// Reads all the text from a FileInfo object.
|
||||
/// </summary>
|
||||
/// <param name="file">The file to read from.</param>
|
||||
/// <returns>The text contents.</returns>
|
||||
public static string ReadAllText(this FileInfo file)
|
||||
{
|
||||
return File.ReadAllText(file.FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the text from a FileInfo object.
|
||||
/// </summary>
|
||||
/// <param name="file">The file to read from.</param>
|
||||
/// <param name="encoding">The encoding to use.</param>
|
||||
/// <returns>The text contents.</returns>
|
||||
public static string ReadAllText(this FileInfo file, Encoding encoding)
|
||||
{
|
||||
return File.ReadAllText(file.FullName, encoding);
|
||||
}
|
||||
/// <summary>
|
||||
/// Reads all the text from a FileInfo object.
|
||||
/// </summary>
|
||||
/// <param name="file">The file to read from.</param>
|
||||
/// <param name="encoding">The encoding to use.</param>
|
||||
/// <returns>The text contents.</returns>
|
||||
public static string ReadAllText(this FileInfo file, Encoding encoding)
|
||||
{
|
||||
return File.ReadAllText(file.FullName, encoding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes out all the text to the given file.
|
||||
/// </summary>
|
||||
/// <param name="file">The file to write to.</param>
|
||||
/// <param name="text">The text to write out.</param>
|
||||
public static void WriteAllText(this FileInfo file, string text)
|
||||
{
|
||||
File.WriteAllText(file.FullName, text);
|
||||
}
|
||||
/// <summary>
|
||||
/// Writes out all the text to the given file.
|
||||
/// </summary>
|
||||
/// <param name="file">The file to write to.</param>
|
||||
/// <param name="text">The text to write out.</param>
|
||||
public static void WriteAllText(this FileInfo file, string text)
|
||||
{
|
||||
File.WriteAllText(file.FullName, text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes out all the text to the given file.
|
||||
/// </summary>
|
||||
/// <param name="file">The file to write to.</param>
|
||||
/// <param name="text">The text to write out.</param>
|
||||
/// <param name="encoding">The encoding to use.</param>
|
||||
public static void WriteAllText(
|
||||
this FileInfo file,
|
||||
string text,
|
||||
Encoding encoding)
|
||||
{
|
||||
File.WriteAllText(file.FullName, text, encoding);
|
||||
}
|
||||
/// <summary>
|
||||
/// Writes out all the text to the given file.
|
||||
/// </summary>
|
||||
/// <param name="file">The file to write to.</param>
|
||||
/// <param name="text">The text to write out.</param>
|
||||
/// <param name="encoding">The encoding to use.</param>
|
||||
public static void WriteAllText(this FileInfo file, string text, Encoding encoding)
|
||||
{
|
||||
File.WriteAllText(file.FullName, text, encoding);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,23 +5,23 @@ namespace MfGames.IO.Extensions;
|
|||
/// </summary>
|
||||
public static class TypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the directory for a given type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type assembly to get the directory.</param>
|
||||
/// <returns>The directory or null if the assembly or location is null.</returns>
|
||||
public static DirectoryInfo? GetDirectory(this Type? type)
|
||||
{
|
||||
return type?.Assembly.GetDirectory();
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the directory for a given type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type assembly to get the directory.</param>
|
||||
/// <returns>The directory or null if the assembly or location is null.</returns>
|
||||
public static DirectoryInfo? GetDirectory(this Type? type)
|
||||
{
|
||||
return type?.Assembly.GetDirectory();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file for a given type's assembly.
|
||||
/// </summary>
|
||||
/// <param name="type">The type assembly to get the directory.</param>
|
||||
/// <returns>The directory or null if the assembly or location is null.</returns>
|
||||
public static FileInfo? GetFile(this Type? type)
|
||||
{
|
||||
return type?.Assembly.GetFile();
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the file for a given type's assembly.
|
||||
/// </summary>
|
||||
/// <param name="type">The type assembly to get the directory.</param>
|
||||
/// <returns>The directory or null if the assembly or location is null.</returns>
|
||||
public static FileInfo? GetFile(this Type? type)
|
||||
{
|
||||
return type?.Assembly.GetFile();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,39 +5,41 @@
|
|||
/// </summary>
|
||||
public class NestableReadLock : IDisposable
|
||||
{
|
||||
private readonly bool lockAcquired;
|
||||
private readonly bool lockAcquired;
|
||||
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NestableReadLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public NestableReadLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
// Keep track of the lock since we'll need it to release the lock.
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NestableReadLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public NestableReadLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
// Keep track of the lock since we'll need it to release the lock.
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
|
||||
// If we already have a read or write lock, we don't do anything.
|
||||
if (readerWriterLockSlim.IsReadLockHeld
|
||||
|| readerWriterLockSlim.IsUpgradeableReadLockHeld
|
||||
|| readerWriterLockSlim.IsWriteLockHeld)
|
||||
{
|
||||
this.lockAcquired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
readerWriterLockSlim.EnterReadLock();
|
||||
this.lockAcquired = true;
|
||||
}
|
||||
}
|
||||
// If we already have a read or write lock, we don't do anything.
|
||||
if (
|
||||
readerWriterLockSlim.IsReadLockHeld
|
||||
|| readerWriterLockSlim.IsUpgradeableReadLockHeld
|
||||
|| readerWriterLockSlim.IsWriteLockHeld
|
||||
)
|
||||
{
|
||||
this.lockAcquired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
readerWriterLockSlim.EnterReadLock();
|
||||
this.lockAcquired = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.lockAcquired)
|
||||
{
|
||||
this.readerWriterLockSlim.ExitReadLock();
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.lockAcquired)
|
||||
{
|
||||
this.readerWriterLockSlim.ExitReadLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,39 +5,38 @@
|
|||
/// </summary>
|
||||
public class NestableUpgradableReadLock : IDisposable
|
||||
{
|
||||
private readonly bool lockAcquired;
|
||||
private readonly bool lockAcquired;
|
||||
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NestableUpgradableReadLock" />
|
||||
/// class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public NestableUpgradableReadLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
// Keep track of the lock since we'll need it to release the lock.
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NestableUpgradableReadLock" />
|
||||
/// class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public NestableUpgradableReadLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
// Keep track of the lock since we'll need it to release the lock.
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
|
||||
// If we already have a read or write lock, we don't do anything.
|
||||
if (readerWriterLockSlim.IsUpgradeableReadLockHeld
|
||||
|| readerWriterLockSlim.IsWriteLockHeld)
|
||||
{
|
||||
this.lockAcquired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
readerWriterLockSlim.EnterUpgradeableReadLock();
|
||||
this.lockAcquired = true;
|
||||
}
|
||||
}
|
||||
// If we already have a read or write lock, we don't do anything.
|
||||
if (readerWriterLockSlim.IsUpgradeableReadLockHeld || readerWriterLockSlim.IsWriteLockHeld)
|
||||
{
|
||||
this.lockAcquired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
readerWriterLockSlim.EnterUpgradeableReadLock();
|
||||
this.lockAcquired = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.lockAcquired)
|
||||
{
|
||||
this.readerWriterLockSlim.ExitUpgradeableReadLock();
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.lockAcquired)
|
||||
{
|
||||
this.readerWriterLockSlim.ExitUpgradeableReadLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,37 +5,37 @@
|
|||
/// </summary>
|
||||
public class NestableWriteLock : IDisposable
|
||||
{
|
||||
private readonly bool lockAcquired;
|
||||
private readonly bool lockAcquired;
|
||||
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NestableWriteLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public NestableWriteLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
// Keep track of the lock since we'll need it to release the lock.
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NestableWriteLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public NestableWriteLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
// Keep track of the lock since we'll need it to release the lock.
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
|
||||
// If we already have a read or write lock, we don't do anything.
|
||||
if (readerWriterLockSlim.IsWriteLockHeld)
|
||||
{
|
||||
this.lockAcquired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
readerWriterLockSlim.EnterWriteLock();
|
||||
this.lockAcquired = true;
|
||||
}
|
||||
}
|
||||
// If we already have a read or write lock, we don't do anything.
|
||||
if (readerWriterLockSlim.IsWriteLockHeld)
|
||||
{
|
||||
this.lockAcquired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
readerWriterLockSlim.EnterWriteLock();
|
||||
this.lockAcquired = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.lockAcquired)
|
||||
{
|
||||
this.readerWriterLockSlim.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.lockAcquired)
|
||||
{
|
||||
this.readerWriterLockSlim.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,21 +6,21 @@
|
|||
/// </summary>
|
||||
public class ReadLock : IDisposable
|
||||
{
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReadLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public ReadLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
readerWriterLockSlim.EnterReadLock();
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReadLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public ReadLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
readerWriterLockSlim.EnterReadLock();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
this.readerWriterLockSlim.ExitReadLock();
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
this.readerWriterLockSlim.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,24 +5,24 @@ namespace MfGames.Locking;
|
|||
/// </summary>
|
||||
public class UpgradableLock : IDisposable
|
||||
{
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UpgradableLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public UpgradableLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
readerWriterLockSlim.EnterUpgradeableReadLock();
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UpgradableLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public UpgradableLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
readerWriterLockSlim.EnterUpgradeableReadLock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or
|
||||
/// resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.readerWriterLockSlim.ExitUpgradeableReadLock();
|
||||
}
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or
|
||||
/// resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.readerWriterLockSlim.ExitUpgradeableReadLock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,24 +5,24 @@ namespace MfGames.Locking;
|
|||
/// </summary>
|
||||
public class WriteLock : IDisposable
|
||||
{
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
private readonly ReaderWriterLockSlim readerWriterLockSlim;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WriteLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public WriteLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
readerWriterLockSlim.EnterWriteLock();
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WriteLock" /> class.
|
||||
/// </summary>
|
||||
/// <param name="readerWriterLockSlim">The reader writer lock slim.</param>
|
||||
public WriteLock(ReaderWriterLockSlim readerWriterLockSlim)
|
||||
{
|
||||
this.readerWriterLockSlim = readerWriterLockSlim;
|
||||
readerWriterLockSlim.EnterWriteLock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or
|
||||
/// resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.readerWriterLockSlim.ExitWriteLock();
|
||||
}
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or
|
||||
/// resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.readerWriterLockSlim.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ using Markdig;
|
|||
using Markdig.Extensions.Tables;
|
||||
using Markdig.Parsers.Inlines;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
||||
|
||||
|
@ -14,52 +13,52 @@ namespace MfGames.Markdown.Gemtext.Extensions;
|
|||
/// <seealso cref="IMarkdownExtension" />
|
||||
public class GemtextPipeTableExtension : IMarkdownExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GemtextPipeTableExtension" />
|
||||
/// class.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
public GemtextPipeTableExtension(GemtextPipeTableOptions? options = null)
|
||||
{
|
||||
this.Options = options ?? new GemtextPipeTableOptions();
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GemtextPipeTableExtension" />
|
||||
/// class.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
public GemtextPipeTableExtension(GemtextPipeTableOptions? options = null)
|
||||
{
|
||||
this.Options = options ?? new GemtextPipeTableOptions();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the options.
|
||||
/// </summary>
|
||||
public GemtextPipeTableOptions Options { get; }
|
||||
/// <summary>
|
||||
/// Gets the options.
|
||||
/// </summary>
|
||||
public GemtextPipeTableOptions Options { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.PreciseSourceLocation = true;
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.PreciseSourceLocation = true;
|
||||
|
||||
if (!pipeline.BlockParsers.Contains<PipeTableBlockParser>())
|
||||
{
|
||||
pipeline.BlockParsers.Insert(0, new PipeTableBlockParser());
|
||||
}
|
||||
if (!pipeline.BlockParsers.Contains<PipeTableBlockParser>())
|
||||
{
|
||||
pipeline.BlockParsers.Insert(0, new PipeTableBlockParser());
|
||||
}
|
||||
|
||||
LineBreakInlineParser? lineBreakParser =
|
||||
pipeline.InlineParsers.FindExact<LineBreakInlineParser>();
|
||||
LineBreakInlineParser? lineBreakParser =
|
||||
pipeline.InlineParsers.FindExact<LineBreakInlineParser>();
|
||||
|
||||
if (!pipeline.InlineParsers.Contains<PipeTableParser>())
|
||||
{
|
||||
pipeline.InlineParsers.InsertBefore<EmphasisInlineParser>(
|
||||
new PipeTableParser(lineBreakParser!, this.Options));
|
||||
}
|
||||
}
|
||||
if (!pipeline.InlineParsers.Contains<PipeTableParser>())
|
||||
{
|
||||
pipeline.InlineParsers.InsertBefore<EmphasisInlineParser>(
|
||||
new PipeTableParser(lineBreakParser!, this.Options)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gemtext.ObjectRenderers.Add(
|
||||
new TableRenderer(
|
||||
this.Options.OmitPreformatLines,
|
||||
this.Options.ConfigureTableBuilder));
|
||||
}
|
||||
gemtext.ObjectRenderers.Add(
|
||||
new TableRenderer(this.Options.OmitPreformatLines, this.Options.ConfigureTableBuilder)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
using ConsoleTableExt;
|
||||
|
||||
using Markdig.Extensions.Tables;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Extensions;
|
||||
|
||||
public class GemtextPipeTableOptions : PipeTableOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the table builder to control formatting.
|
||||
/// </summary>
|
||||
public Action<ConsoleTableBuilder>? ConfigureTableBuilder { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the table builder to control formatting.
|
||||
/// </summary>
|
||||
public Action<ConsoleTableBuilder>? ConfigureTableBuilder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value whether the preformat (backticks) fence should
|
||||
/// not be emitted.
|
||||
/// </summary>
|
||||
public bool OmitPreformatLines { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value whether the preformat (backticks) fence should
|
||||
/// not be emitted.
|
||||
/// </summary>
|
||||
public bool OmitPreformatLines { get; set; }
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ using Markdig;
|
|||
using Markdig.Extensions.SmartyPants;
|
||||
using Markdig.Parsers.Inlines;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
||||
|
||||
|
@ -13,42 +12,39 @@ namespace MfGames.Markdown.Gemtext.Extensions;
|
|||
/// </summary>
|
||||
public class GemtextSmartyPantsExtension : IMarkdownExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SmartyPantsExtension" /> class.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
public GemtextSmartyPantsExtension(SmartyPantOptions? options)
|
||||
{
|
||||
this.Options = options ?? new SmartyPantOptions();
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SmartyPantsExtension" /> class.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
public GemtextSmartyPantsExtension(SmartyPantOptions? options)
|
||||
{
|
||||
this.Options = options ?? new SmartyPantOptions();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the options.
|
||||
/// </summary>
|
||||
public SmartyPantOptions Options { get; }
|
||||
/// <summary>
|
||||
/// Gets the options.
|
||||
/// </summary>
|
||||
public SmartyPantOptions Options { get; }
|
||||
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.InlineParsers.Contains<SmartyPantsInlineParser>())
|
||||
{
|
||||
// Insert the parser after the code span parser
|
||||
pipeline.InlineParsers.InsertAfter<CodeInlineParser>(
|
||||
new SmartyPantsInlineParser());
|
||||
}
|
||||
}
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.InlineParsers.Contains<SmartyPantsInlineParser>())
|
||||
{
|
||||
// Insert the parser after the code span parser
|
||||
pipeline.InlineParsers.InsertAfter<CodeInlineParser>(new SmartyPantsInlineParser());
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtextRenderer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtextRenderer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gemtextRenderer.ObjectRenderers
|
||||
.Contains<GemtextSmartyPantRenderer>())
|
||||
{
|
||||
gemtextRenderer.ObjectRenderers.Add(
|
||||
new GemtextSmartyPantRenderer(this.Options));
|
||||
}
|
||||
}
|
||||
if (!gemtextRenderer.ObjectRenderers.Contains<GemtextSmartyPantRenderer>())
|
||||
{
|
||||
gemtextRenderer.ObjectRenderers.Add(new GemtextSmartyPantRenderer(this.Options));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Markdig;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Extensions;
|
||||
|
@ -12,17 +11,15 @@ namespace MfGames.Markdown.Gemtext.Extensions;
|
|||
/// <seealso cref="IMarkdownExtension" />
|
||||
public class HtmlAsCodeBlocks : IMarkdownExtension
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is GemtextRenderer gemtext)
|
||||
{
|
||||
gemtext.HtmlBlockFormatting = HtmlBlockFormatting.CodeBlock;
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is GemtextRenderer gemtext)
|
||||
{
|
||||
gemtext.HtmlBlockFormatting = HtmlBlockFormatting.CodeBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Markdig;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
||||
|
||||
|
@ -14,25 +13,22 @@ namespace MfGames.Markdown.Gemtext.Extensions;
|
|||
/// <seealso cref="IMarkdownExtension" />
|
||||
public class IncreaseHeaderDepthsAfterFirst : IMarkdownExtension
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HeadingRenderer? heading =
|
||||
gemtext.ObjectRenderers.Find<HeadingRenderer>();
|
||||
HeadingRenderer? heading = gemtext.ObjectRenderers.Find<HeadingRenderer>();
|
||||
|
||||
if (heading != null)
|
||||
{
|
||||
heading.IncreaseHeaderDepthAfterFirst = true;
|
||||
}
|
||||
}
|
||||
if (heading != null)
|
||||
{
|
||||
heading.IncreaseHeaderDepthAfterFirst = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Markdig;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Extensions;
|
||||
|
@ -11,53 +10,50 @@ namespace MfGames.Markdown.Gemtext.Extensions;
|
|||
/// <seealso cref="IMarkdownExtension" />
|
||||
public class SetBlockLinkHandling : IMarkdownExtension
|
||||
{
|
||||
public SetBlockLinkHandling(
|
||||
BlockLinkHandling? blockLinkHandling = null,
|
||||
EndLinkInlineFormatting? endLinkInlineFormatting = null,
|
||||
int? nextFootnoteNumber = null)
|
||||
{
|
||||
this.BlockLinkHandling = blockLinkHandling;
|
||||
this.EndLinkInlineFormatting = endLinkInlineFormatting;
|
||||
this.NextFootnoteNumber = nextFootnoteNumber;
|
||||
}
|
||||
public SetBlockLinkHandling(
|
||||
BlockLinkHandling? blockLinkHandling = null,
|
||||
EndLinkInlineFormatting? endLinkInlineFormatting = null,
|
||||
int? nextFootnoteNumber = null
|
||||
)
|
||||
{
|
||||
this.BlockLinkHandling = blockLinkHandling;
|
||||
this.EndLinkInlineFormatting = endLinkInlineFormatting;
|
||||
this.NextFootnoteNumber = nextFootnoteNumber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how block links are handled. If this is null, then no
|
||||
/// change is made to the current renderer.
|
||||
/// </summary>
|
||||
public BlockLinkHandling? BlockLinkHandling { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets how block links are handled. If this is null, then no
|
||||
/// change is made to the current renderer.
|
||||
/// </summary>
|
||||
public BlockLinkHandling? BlockLinkHandling { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how links are formatted if they are gathered to the
|
||||
/// end of the paragraph or document. If this is null, then no change
|
||||
/// will be made.
|
||||
/// </summary>
|
||||
public EndLinkInlineFormatting? EndLinkInlineFormatting { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets how links are formatted if they are gathered to the
|
||||
/// end of the paragraph or document. If this is null, then no change
|
||||
/// will be made.
|
||||
/// </summary>
|
||||
public EndLinkInlineFormatting? EndLinkInlineFormatting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the next footnote number. If this is null, then no
|
||||
/// change will be made.
|
||||
/// </summary>
|
||||
public int? NextFootnoteNumber { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the next footnote number. If this is null, then no
|
||||
/// change will be made.
|
||||
/// </summary>
|
||||
public int? NextFootnoteNumber { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gemtext.BlockLinkHandling = this.BlockLinkHandling
|
||||
?? gemtext.BlockLinkHandling;
|
||||
gemtext.EndLinkInlineFormatting = this.EndLinkInlineFormatting
|
||||
?? gemtext.EndLinkInlineFormatting;
|
||||
gemtext.NextFootnoteNumber = this.NextFootnoteNumber
|
||||
?? gemtext.NextFootnoteNumber;
|
||||
}
|
||||
gemtext.BlockLinkHandling = this.BlockLinkHandling ?? gemtext.BlockLinkHandling;
|
||||
gemtext.EndLinkInlineFormatting =
|
||||
this.EndLinkInlineFormatting ?? gemtext.EndLinkInlineFormatting;
|
||||
gemtext.NextFootnoteNumber = this.NextFootnoteNumber ?? gemtext.NextFootnoteNumber;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using Markdig;
|
||||
using Markdig.Renderers;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Extensions;
|
||||
|
@ -12,38 +11,36 @@ namespace MfGames.Markdown.Gemtext.Extensions;
|
|||
/// <seealso cref="IMarkdownExtension" />
|
||||
public class SetInlineFormatting : IMarkdownExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the override formatting for code lines
|
||||
/// (backtick) spans.
|
||||
/// </summary>
|
||||
public InlineFormatting? Code { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the override formatting for code lines
|
||||
/// (backtick) spans.
|
||||
/// </summary>
|
||||
public InlineFormatting? Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets or sets the override formatting for all inlines.
|
||||
/// </summary>
|
||||
public InlineFormatting? Default { get; set; }
|
||||
/// <summary>
|
||||
/// Sets or sets the override formatting for all inlines.
|
||||
/// </summary>
|
||||
public InlineFormatting? Default { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the override formatting for emphasis (italic
|
||||
/// and bold) spans.
|
||||
/// </summary>
|
||||
public InlineFormatting? Emphasis { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the override formatting for emphasis (italic
|
||||
/// and bold) spans.
|
||||
/// </summary>
|
||||
public InlineFormatting? Emphasis { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
if (renderer is not GemtextRenderer gemtext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gemtext.InlineFormatting = this.Default ?? gemtext.InlineFormatting;
|
||||
gemtext.EmphasisFormatting = this.Emphasis;
|
||||
gemtext.CodeFormatting = this.Code;
|
||||
}
|
||||
gemtext.InlineFormatting = this.Default ?? gemtext.InlineFormatting;
|
||||
gemtext.EmphasisFormatting = this.Emphasis;
|
||||
gemtext.CodeFormatting = this.Code;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using Markdig;
|
||||
using Markdig.Parsers;
|
||||
using Markdig.Syntax;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext;
|
||||
|
@ -13,69 +12,69 @@ namespace MfGames.Markdown.Gemtext;
|
|||
/// </summary>
|
||||
public static class MarkdownGemtext
|
||||
{
|
||||
private static readonly MarkdownPipeline DefaultPipeline;
|
||||
private static readonly MarkdownPipeline DefaultPipeline;
|
||||
|
||||
static MarkdownGemtext()
|
||||
{
|
||||
DefaultPipeline = new MarkdownPipelineBuilder()
|
||||
.Build();
|
||||
}
|
||||
static MarkdownGemtext()
|
||||
{
|
||||
DefaultPipeline = new MarkdownPipelineBuilder().Build();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given Markdown
|
||||
/// </summary>
|
||||
/// <param name="markdown">A Markdown text.</param>
|
||||
/// <param name="pipeline">The pipeline used for the conversion.</param>
|
||||
/// <param name="context">A parser context used for the parsing.</param>
|
||||
/// <returns>The result of the conversion</returns>
|
||||
public static string ToGemtext(
|
||||
string markdown,
|
||||
MarkdownPipeline? pipeline = null,
|
||||
MarkdownParserContext? context = null)
|
||||
{
|
||||
if (markdown == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(markdown));
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the given Markdown
|
||||
/// </summary>
|
||||
/// <param name="markdown">A Markdown text.</param>
|
||||
/// <param name="pipeline">The pipeline used for the conversion.</param>
|
||||
/// <param name="context">A parser context used for the parsing.</param>
|
||||
/// <returns>The result of the conversion</returns>
|
||||
public static string ToGemtext(
|
||||
string markdown,
|
||||
MarkdownPipeline? pipeline = null,
|
||||
MarkdownParserContext? context = null
|
||||
)
|
||||
{
|
||||
if (markdown == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(markdown));
|
||||
}
|
||||
|
||||
pipeline ??= DefaultPipeline;
|
||||
pipeline ??= DefaultPipeline;
|
||||
|
||||
MarkdownDocument document = MarkdownParser
|
||||
.Parse(markdown, pipeline, context);
|
||||
MarkdownDocument document = MarkdownParser.Parse(markdown, pipeline, context);
|
||||
|
||||
return ToGemtext(document, pipeline);
|
||||
}
|
||||
return ToGemtext(document, pipeline);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Markdown document to HTML.
|
||||
/// </summary>
|
||||
/// <param name="document">A Markdown document.</param>
|
||||
/// <param name="pipeline">The pipeline used for the conversion.</param>
|
||||
/// <returns>The result of the conversion</returns>
|
||||
/// <exception cref="ArgumentNullException">if markdown document variable is null</exception>
|
||||
public static string ToGemtext(
|
||||
this MarkdownDocument document,
|
||||
MarkdownPipeline? pipeline = null)
|
||||
{
|
||||
// Make sure we have sane parameters.
|
||||
if (document == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(document));
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts a Markdown document to HTML.
|
||||
/// </summary>
|
||||
/// <param name="document">A Markdown document.</param>
|
||||
/// <param name="pipeline">The pipeline used for the conversion.</param>
|
||||
/// <returns>The result of the conversion</returns>
|
||||
/// <exception cref="ArgumentNullException">if markdown document variable is null</exception>
|
||||
public static string ToGemtext(
|
||||
this MarkdownDocument document,
|
||||
MarkdownPipeline? pipeline = null
|
||||
)
|
||||
{
|
||||
// Make sure we have sane parameters.
|
||||
if (document == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(document));
|
||||
}
|
||||
|
||||
pipeline ??= DefaultPipeline;
|
||||
pipeline ??= DefaultPipeline;
|
||||
|
||||
// Set up the writer to contain the markdown and the Gemtext
|
||||
// renderer.
|
||||
var writer = new StringWriter();
|
||||
GemtextRenderer renderer = new(writer);
|
||||
// Set up the writer to contain the markdown and the Gemtext
|
||||
// renderer.
|
||||
var writer = new StringWriter();
|
||||
GemtextRenderer renderer = new(writer);
|
||||
|
||||
pipeline.Setup(renderer);
|
||||
pipeline.Setup(renderer);
|
||||
|
||||
// Render the Markdown into Gemtext and re turn the results.
|
||||
renderer.Render(document);
|
||||
renderer.Writer.Flush();
|
||||
// Render the Markdown into Gemtext and re turn the results.
|
||||
renderer.Render(document);
|
||||
renderer.Writer.Flush();
|
||||
|
||||
return renderer.Writer.ToString() ?? string.Empty;
|
||||
}
|
||||
return renderer.Writer.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,29 +5,29 @@ namespace MfGames.Markdown.Gemtext.Renderers;
|
|||
/// </summary>
|
||||
public enum BlockLinkHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that the paragraph should be broken apart and the link
|
||||
/// included on its own line in the middle of the paragraph.
|
||||
/// </summary>
|
||||
InsertLine,
|
||||
/// <summary>
|
||||
/// Indicates that the paragraph should be broken apart and the link
|
||||
/// included on its own line in the middle of the paragraph.
|
||||
/// </summary>
|
||||
InsertLine,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that all the links in a paragraph should be gathered
|
||||
/// and then emitted at the end of the paragraph. The text of the link
|
||||
/// will be left in the paragraph.
|
||||
/// </summary>
|
||||
ParagraphEnd,
|
||||
/// <summary>
|
||||
/// Indicates that all the links in a paragraph should be gathered
|
||||
/// and then emitted at the end of the paragraph. The text of the link
|
||||
/// will be left in the paragraph.
|
||||
/// </summary>
|
||||
ParagraphEnd,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that all the links in the document should be gathered
|
||||
/// and then emitted at the end of the document. The text of the link
|
||||
/// will be left in the paragraph.
|
||||
/// </summary>
|
||||
DocumentEnd,
|
||||
/// <summary>
|
||||
/// Indicates that all the links in the document should be gathered
|
||||
/// and then emitted at the end of the document. The text of the link
|
||||
/// will be left in the paragraph.
|
||||
/// </summary>
|
||||
DocumentEnd,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the links themselves should be removed and just the
|
||||
/// text included in the paragraph.
|
||||
/// </summary>
|
||||
Remove,
|
||||
/// <summary>
|
||||
/// Indicates that the links themselves should be removed and just the
|
||||
/// text included in the paragraph.
|
||||
/// </summary>
|
||||
Remove,
|
||||
}
|
||||
|
|
|
@ -7,15 +7,15 @@ namespace MfGames.Markdown.Gemtext.Renderers;
|
|||
/// </summary>
|
||||
public enum EndLinkInlineFormatting
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a footnote notation (`[1]`) will be insert into the
|
||||
/// text and then the link will be displayed with the URL when gathered.
|
||||
/// </summary>
|
||||
Footnote,
|
||||
/// <summary>
|
||||
/// Indicates that a footnote notation (`[1]`) will be insert into the
|
||||
/// text and then the link will be displayed with the URL when gathered.
|
||||
/// </summary>
|
||||
Footnote,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the text is put in as-is into the gathered link with
|
||||
/// no footnote given in the block.
|
||||
/// </summary>
|
||||
Text,
|
||||
/// <summary>
|
||||
/// Indicates that the text is put in as-is into the gathered link with
|
||||
/// no footnote given in the block.
|
||||
/// </summary>
|
||||
Text,
|
||||
}
|
||||
|
|
|
@ -9,30 +9,30 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
|||
/// <seealso cref="GemtextObjectRenderer{CodeBlock}" />
|
||||
public class CodeBlockRenderer : GemtextObjectRenderer<CodeBlock>
|
||||
{
|
||||
protected override void Write(GemtextRenderer renderer, CodeBlock obj)
|
||||
{
|
||||
// We need to have two lines above this.
|
||||
renderer.EnsureTwoLines();
|
||||
protected override void Write(GemtextRenderer renderer, CodeBlock obj)
|
||||
{
|
||||
// We need to have two lines above this.
|
||||
renderer.EnsureTwoLines();
|
||||
|
||||
// Code blocks are always fenced, but we allow for additional text
|
||||
// at the end of them which is only in `FencedCodeBlock`.
|
||||
if (obj is FencedCodeBlock fenced)
|
||||
{
|
||||
renderer.WriteLine("```" + fenced.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.WriteLine("```");
|
||||
}
|
||||
// Code blocks are always fenced, but we allow for additional text
|
||||
// at the end of them which is only in `FencedCodeBlock`.
|
||||
if (obj is FencedCodeBlock fenced)
|
||||
{
|
||||
renderer.WriteLine("```" + fenced.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.WriteLine("```");
|
||||
}
|
||||
|
||||
renderer.WriteLeafRawLines(obj, true);
|
||||
renderer.Write("```");
|
||||
renderer.WriteLeafRawLines(obj, true);
|
||||
renderer.Write("```");
|
||||
|
||||
// If we aren't at the end of the container, then add some spacing.
|
||||
if (!renderer.IsLastInContainer)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
// If we aren't at the end of the container, then add some spacing.
|
||||
if (!renderer.IsLastInContainer)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,15 +8,15 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
|||
/// <seealso cref="GemtextObjectRenderer{CodeBlock}" />
|
||||
public class CustomContainerRenderer : GemtextObjectRenderer<CustomContainer>
|
||||
{
|
||||
protected override void Write(GemtextRenderer renderer, CustomContainer obj)
|
||||
{
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.WriteChildren(obj);
|
||||
protected override void Write(GemtextRenderer renderer, CustomContainer obj)
|
||||
{
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.WriteChildren(obj);
|
||||
|
||||
if (!renderer.IsLastInContainer)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
if (!renderer.IsLastInContainer)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,48 +8,46 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
|||
/// <seealso cref="GemtextObjectRenderer{HeadingBlock}" />
|
||||
public class HeadingRenderer : GemtextObjectRenderer<HeadingBlock>
|
||||
{
|
||||
private int currentHeading;
|
||||
private int currentHeading;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the header depths are
|
||||
/// increased after the first one.
|
||||
/// </summary>
|
||||
public bool IncreaseHeaderDepthAfterFirst { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the header depths are
|
||||
/// increased after the first one.
|
||||
/// </summary>
|
||||
public bool IncreaseHeaderDepthAfterFirst { get; set; }
|
||||
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
HeadingBlock obj)
|
||||
{
|
||||
// Figure out the level we should be processing.
|
||||
int level = obj.Level;
|
||||
protected override void Write(GemtextRenderer renderer, HeadingBlock obj)
|
||||
{
|
||||
// Figure out the level we should be processing.
|
||||
int level = obj.Level;
|
||||
|
||||
if (this.currentHeading++ > 0 && this.IncreaseHeaderDepthAfterFirst)
|
||||
{
|
||||
// Check the second header we see. If this header is H2 or
|
||||
// higher, then we assume that the file has been already updated
|
||||
// to handle the heading and we stop processing.
|
||||
if (this.currentHeading == 2 && level != 1)
|
||||
{
|
||||
this.IncreaseHeaderDepthAfterFirst = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are bumping the heading levels up.
|
||||
level++;
|
||||
}
|
||||
}
|
||||
if (this.currentHeading++ > 0 && this.IncreaseHeaderDepthAfterFirst)
|
||||
{
|
||||
// Check the second header we see. If this header is H2 or
|
||||
// higher, then we assume that the file has been already updated
|
||||
// to handle the heading and we stop processing.
|
||||
if (this.currentHeading == 2 && level != 1)
|
||||
{
|
||||
this.IncreaseHeaderDepthAfterFirst = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are bumping the heading levels up.
|
||||
level++;
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the prefix of the header.
|
||||
string prefix = level switch
|
||||
{
|
||||
1 => "# ",
|
||||
2 => "## ",
|
||||
3 => "### ",
|
||||
_ => "",
|
||||
};
|
||||
// Write out the prefix of the header.
|
||||
string prefix = level switch
|
||||
{
|
||||
1 => "# ",
|
||||
2 => "## ",
|
||||
3 => "### ",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.Write(prefix);
|
||||
renderer.WriteLeafInline(obj);
|
||||
}
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.Write(prefix);
|
||||
renderer.WriteLeafInline(obj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,25 +8,25 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
|||
/// <seealso cref="GemtextObjectRenderer{GemtextBlock}" />
|
||||
public class HtmlBlockRenderer : GemtextObjectRenderer<HtmlBlock>
|
||||
{
|
||||
protected override void Write(GemtextRenderer renderer, HtmlBlock obj)
|
||||
{
|
||||
// If we are stripping out HTML blocks (default), then nothing to
|
||||
// do with rendering.
|
||||
if (renderer.HtmlBlockFormatting == HtmlBlockFormatting.Remove)
|
||||
{
|
||||
return;
|
||||
}
|
||||
protected override void Write(GemtextRenderer renderer, HtmlBlock obj)
|
||||
{
|
||||
// If we are stripping out HTML blocks (default), then nothing to
|
||||
// do with rendering.
|
||||
if (renderer.HtmlBlockFormatting == HtmlBlockFormatting.Remove)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we treat this as a fenced code block.
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.WriteLine("```html");
|
||||
renderer.WriteLeafRawLines(obj, true);
|
||||
renderer.WriteLine("```");
|
||||
// Otherwise, we treat this as a fenced code block.
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.WriteLine("```html");
|
||||
renderer.WriteLeafRawLines(obj, true);
|
||||
renderer.WriteLine("```");
|
||||
|
||||
// If we aren't at the end of the container, then add some spacing.
|
||||
if (!renderer.IsLastInContainer)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
// If we aren't at the end of the container, then add some spacing.
|
||||
if (!renderer.IsLastInContainer)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,27 +8,25 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
|||
/// <seealso cref="GemtextObjectRenderer{ListBlock}" />
|
||||
public class ListRenderer : GemtextObjectRenderer<ListBlock>
|
||||
{
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
ListBlock listBlock)
|
||||
{
|
||||
// Lists need to be separated from the rest.
|
||||
renderer.EnsureTwoLines();
|
||||
protected override void Write(GemtextRenderer renderer, ListBlock listBlock)
|
||||
{
|
||||
// Lists need to be separated from the rest.
|
||||
renderer.EnsureTwoLines();
|
||||
|
||||
// Go through each list item and write them out.
|
||||
foreach (Block? item in listBlock)
|
||||
{
|
||||
// If the list only contains a link, then we just render the
|
||||
// link instead.
|
||||
var listItem = (ListItemBlock)item;
|
||||
// Go through each list item and write them out.
|
||||
foreach (Block? item in listBlock)
|
||||
{
|
||||
// If the list only contains a link, then we just render the
|
||||
// link instead.
|
||||
var listItem = (ListItemBlock)item;
|
||||
|
||||
if (!listItem.OnlyHasSingleLink())
|
||||
{
|
||||
renderer.EnsureLine();
|
||||
renderer.Write("* ");
|
||||
}
|
||||
if (!listItem.OnlyHasSingleLink())
|
||||
{
|
||||
renderer.EnsureLine();
|
||||
renderer.Write("* ");
|
||||
}
|
||||
|
||||
renderer.WriteChildren(listItem);
|
||||
}
|
||||
}
|
||||
renderer.WriteChildren(listItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Markdig.Syntax;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
||||
|
@ -8,20 +7,17 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
|||
/// A Gemtext renderer for a <see cref="MarkdownDocument" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="GemtextObjectRenderer{ParagraphBlock}" />
|
||||
public class MarkdownDocumentRenderer
|
||||
: GemtextObjectRenderer<MarkdownDocument>
|
||||
public class MarkdownDocumentRenderer : GemtextObjectRenderer<MarkdownDocument>
|
||||
{
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
MarkdownDocument obj)
|
||||
{
|
||||
// Simply write out the contents.
|
||||
renderer.WriteChildren(obj);
|
||||
protected override void Write(GemtextRenderer renderer, MarkdownDocument obj)
|
||||
{
|
||||
// Simply write out the contents.
|
||||
renderer.WriteChildren(obj);
|
||||
|
||||
// If we get to the end of the document and we have gathered links,
|
||||
// and we are in DocumentEnd mode, then write out the links. We
|
||||
// don't test for the mode here because if there are links, we
|
||||
// should write them out.
|
||||
LinkInlineRenderer.WriteGatheredLinks(renderer);
|
||||
}
|
||||
// If we get to the end of the document and we have gathered links,
|
||||
// and we are in DocumentEnd mode, then write out the links. We
|
||||
// don't test for the mode here because if there are links, we
|
||||
// should write them out.
|
||||
LinkInlineRenderer.WriteGatheredLinks(renderer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Markdig.Syntax;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
||||
|
@ -10,34 +9,31 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
|||
/// <seealso cref="GemtextObjectRenderer{ParagraphBlock}" />
|
||||
public class ParagraphRenderer : GemtextObjectRenderer<ParagraphBlock>
|
||||
{
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
ParagraphBlock obj)
|
||||
{
|
||||
// If we aren't the first in the container, we need to break apart
|
||||
// the lines to make it easier to read.
|
||||
if (!renderer.IsFirstInContainer)
|
||||
{
|
||||
renderer.EnsureTwoLines();
|
||||
}
|
||||
protected override void Write(GemtextRenderer renderer, ParagraphBlock obj)
|
||||
{
|
||||
// If we aren't the first in the container, we need to break apart
|
||||
// the lines to make it easier to read.
|
||||
if (!renderer.IsFirstInContainer)
|
||||
{
|
||||
renderer.EnsureTwoLines();
|
||||
}
|
||||
|
||||
// We need to save the state of the link rendering while handling
|
||||
// this block.
|
||||
if (obj.OnlyHasSingleLink())
|
||||
{
|
||||
renderer.WriteLeafInline(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.WhileLinkInsideBlock(
|
||||
() => renderer.WriteLeafInline(obj));
|
||||
}
|
||||
// We need to save the state of the link rendering while handling
|
||||
// this block.
|
||||
if (obj.OnlyHasSingleLink())
|
||||
{
|
||||
renderer.WriteLeafInline(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.WhileLinkInsideBlock(() => renderer.WriteLeafInline(obj));
|
||||
}
|
||||
|
||||
// If we get to the end of the paragraph and we have gathered links,
|
||||
// and we are in ParagraphEnd mode, then write out the links.
|
||||
if (renderer.BlockLinkHandling == BlockLinkHandling.ParagraphEnd)
|
||||
{
|
||||
LinkInlineRenderer.WriteGatheredLinks(renderer);
|
||||
}
|
||||
}
|
||||
// If we get to the end of the paragraph and we have gathered links,
|
||||
// and we are in ParagraphEnd mode, then write out the links.
|
||||
if (renderer.BlockLinkHandling == BlockLinkHandling.ParagraphEnd)
|
||||
{
|
||||
LinkInlineRenderer.WriteGatheredLinks(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
|||
/// <seealso cref="GemtextObjectRenderer{QuoteBlock}" />
|
||||
public class QuoteBlockRenderer : GemtextObjectRenderer<QuoteBlock>
|
||||
{
|
||||
protected override void Write(GemtextRenderer renderer, QuoteBlock obj)
|
||||
{
|
||||
string quoteIndent = obj.QuoteChar + " ";
|
||||
protected override void Write(GemtextRenderer renderer, QuoteBlock obj)
|
||||
{
|
||||
string quoteIndent = obj.QuoteChar + " ";
|
||||
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.PushIndent(quoteIndent);
|
||||
renderer.WriteChildren(obj);
|
||||
renderer.PopIndent();
|
||||
}
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.PushIndent(quoteIndent);
|
||||
renderer.WriteChildren(obj);
|
||||
renderer.PopIndent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,131 +1,126 @@
|
|||
using ConsoleTableExt;
|
||||
|
||||
using Markdig.Extensions.Tables;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
||||
|
||||
public class TableRenderer : GemtextObjectRenderer<Table>
|
||||
{
|
||||
private readonly Action<ConsoleTableBuilder>? configureTableBuilder;
|
||||
private readonly Action<ConsoleTableBuilder>? configureTableBuilder;
|
||||
|
||||
private readonly bool omitPreformat;
|
||||
private readonly bool omitPreformat;
|
||||
|
||||
public TableRenderer(
|
||||
bool omitPreformat,
|
||||
Action<ConsoleTableBuilder>? configureTableBuilder)
|
||||
{
|
||||
this.omitPreformat = omitPreformat;
|
||||
this.configureTableBuilder = configureTableBuilder;
|
||||
}
|
||||
public TableRenderer(bool omitPreformat, Action<ConsoleTableBuilder>? configureTableBuilder)
|
||||
{
|
||||
this.omitPreformat = omitPreformat;
|
||||
this.configureTableBuilder = configureTableBuilder;
|
||||
}
|
||||
|
||||
protected override void Write(GemtextRenderer renderer, Table table)
|
||||
{
|
||||
// Since Gemtext doesn't have a table format per-se, we are going
|
||||
// to use ConsoleTableEx to make a nicely-formatted table and emit
|
||||
// the lines directly. That should produce the desired result.
|
||||
protected override void Write(GemtextRenderer renderer, Table table)
|
||||
{
|
||||
// Since Gemtext doesn't have a table format per-se, we are going
|
||||
// to use ConsoleTableEx to make a nicely-formatted table and emit
|
||||
// the lines directly. That should produce the desired result.
|
||||
|
||||
// Gather up information about the data since that is where the
|
||||
// builder starts with.
|
||||
bool hasHeader = false;
|
||||
List<object> header = new();
|
||||
List<List<object>> data = new();
|
||||
Dictionary<int, TextAligntment> align = new();
|
||||
// Gather up information about the data since that is where the
|
||||
// builder starts with.
|
||||
bool hasHeader = false;
|
||||
List<object> header = new();
|
||||
List<List<object>> data = new();
|
||||
Dictionary<int, TextAligntment> align = new();
|
||||
|
||||
foreach (TableRow row in table.OfType<TableRow>())
|
||||
{
|
||||
// If we haven't seen a header, then we include that.
|
||||
if (!hasHeader && row.IsHeader)
|
||||
{
|
||||
header = GetCellValues(row);
|
||||
SetAlignments(table, align, row);
|
||||
continue;
|
||||
}
|
||||
foreach (TableRow row in table.OfType<TableRow>())
|
||||
{
|
||||
// If we haven't seen a header, then we include that.
|
||||
if (!hasHeader && row.IsHeader)
|
||||
{
|
||||
header = GetCellValues(row);
|
||||
SetAlignments(table, align, row);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, we treat it as a row and go through the columns.
|
||||
List<object> cells = GetCellValues(row);
|
||||
// Otherwise, we treat it as a row and go through the columns.
|
||||
List<object> cells = GetCellValues(row);
|
||||
|
||||
data.Add(cells);
|
||||
}
|
||||
data.Add(cells);
|
||||
}
|
||||
|
||||
// Set up the table.
|
||||
ConsoleTableBuilder builder = ConsoleTableBuilder
|
||||
.From(data)
|
||||
.WithColumn(header.OfType<string>().ToArray())
|
||||
.WithHeaderTextAlignment(align)
|
||||
.WithTextAlignment(align);
|
||||
// Set up the table.
|
||||
ConsoleTableBuilder builder = ConsoleTableBuilder
|
||||
.From(data)
|
||||
.WithColumn(header.OfType<string>().ToArray())
|
||||
.WithHeaderTextAlignment(align)
|
||||
.WithTextAlignment(align);
|
||||
|
||||
this.configureTableBuilder?.Invoke(builder);
|
||||
this.configureTableBuilder?.Invoke(builder);
|
||||
|
||||
// Format the final table.
|
||||
string formatted = builder.Export().ToString().TrimEnd();
|
||||
// Format the final table.
|
||||
string formatted = builder.Export().ToString().TrimEnd();
|
||||
|
||||
// Write out the table including making sure two lines are above it.
|
||||
renderer.EnsureTwoLines();
|
||||
// Write out the table including making sure two lines are above it.
|
||||
renderer.EnsureTwoLines();
|
||||
|
||||
if (!this.omitPreformat)
|
||||
{
|
||||
renderer.WriteLine("```");
|
||||
}
|
||||
if (!this.omitPreformat)
|
||||
{
|
||||
renderer.WriteLine("```");
|
||||
}
|
||||
|
||||
renderer.WriteLine(formatted);
|
||||
renderer.WriteLine(formatted);
|
||||
|
||||
if (!this.omitPreformat)
|
||||
{
|
||||
renderer.WriteLine("```");
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
if (!this.omitPreformat)
|
||||
{
|
||||
renderer.WriteLine("```");
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<object> GetCellValues(TableRow row)
|
||||
{
|
||||
List<object> cells = new();
|
||||
private static List<object> GetCellValues(TableRow row)
|
||||
{
|
||||
List<object> cells = new();
|
||||
|
||||
foreach (TableCell cell in row.OfType<TableCell>())
|
||||
{
|
||||
// Write out to a text since we can't have a callback while
|
||||
// rendering the table cells.
|
||||
using var writer = new StringWriter();
|
||||
var innerRenderer = new GemtextRenderer(writer);
|
||||
foreach (TableCell cell in row.OfType<TableCell>())
|
||||
{
|
||||
// Write out to a text since we can't have a callback while
|
||||
// rendering the table cells.
|
||||
using var writer = new StringWriter();
|
||||
var innerRenderer = new GemtextRenderer(writer);
|
||||
|
||||
innerRenderer.Render(cell);
|
||||
cells.Add(writer.ToString());
|
||||
}
|
||||
innerRenderer.Render(cell);
|
||||
cells.Add(writer.ToString());
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
|
||||
private static void SetAlignments(
|
||||
Table table,
|
||||
Dictionary<int, TextAligntment> align,
|
||||
TableRow row)
|
||||
{
|
||||
for (int i = 0; i < row.Count; i++)
|
||||
{
|
||||
// Copied from Markdig's version.
|
||||
var cell = (TableCell)row[i];
|
||||
int columnIndex = cell.ColumnIndex < 0
|
||||
|| cell.ColumnIndex >=
|
||||
table.ColumnDefinitions.Count
|
||||
? i
|
||||
: cell.ColumnIndex;
|
||||
columnIndex =
|
||||
columnIndex >= table.ColumnDefinitions.Count
|
||||
? table.ColumnDefinitions.Count - 1
|
||||
: columnIndex;
|
||||
TableColumnAlign? alignment = table
|
||||
.ColumnDefinitions[columnIndex]
|
||||
.Alignment;
|
||||
private static void SetAlignments(
|
||||
Table table,
|
||||
Dictionary<int, TextAligntment> align,
|
||||
TableRow row
|
||||
)
|
||||
{
|
||||
for (int i = 0; i < row.Count; i++)
|
||||
{
|
||||
// Copied from Markdig's version.
|
||||
var cell = (TableCell)row[i];
|
||||
int columnIndex =
|
||||
cell.ColumnIndex < 0 || cell.ColumnIndex >= table.ColumnDefinitions.Count
|
||||
? i
|
||||
: cell.ColumnIndex;
|
||||
columnIndex =
|
||||
columnIndex >= table.ColumnDefinitions.Count
|
||||
? table.ColumnDefinitions.Count - 1
|
||||
: columnIndex;
|
||||
TableColumnAlign? alignment = table.ColumnDefinitions[columnIndex].Alignment;
|
||||
|
||||
if (alignment.HasValue)
|
||||
{
|
||||
align[columnIndex] = alignment.Value switch
|
||||
{
|
||||
TableColumnAlign.Center => TextAligntment.Center,
|
||||
TableColumnAlign.Left => TextAligntment.Left,
|
||||
TableColumnAlign.Right => TextAligntment.Right,
|
||||
_ => TextAligntment.Left,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (alignment.HasValue)
|
||||
{
|
||||
align[columnIndex] = alignment.Value switch
|
||||
{
|
||||
TableColumnAlign.Center => TextAligntment.Center,
|
||||
TableColumnAlign.Left => TextAligntment.Left,
|
||||
TableColumnAlign.Right => TextAligntment.Right,
|
||||
_ => TextAligntment.Left,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,11 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
|||
/// A Gemtext renderer for a <see cref="ThematicBreakBlock" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="GemtextObjectRenderer{ThematicBreakBlock}" />
|
||||
public class ThematicBreakRenderer
|
||||
: GemtextObjectRenderer<ThematicBreakBlock>
|
||||
public class ThematicBreakRenderer : GemtextObjectRenderer<ThematicBreakBlock>
|
||||
{
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
ThematicBreakBlock obj)
|
||||
{
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.WriteLine("---");
|
||||
}
|
||||
protected override void Write(GemtextRenderer renderer, ThematicBreakBlock obj)
|
||||
{
|
||||
renderer.EnsureTwoLines();
|
||||
renderer.WriteLine("---");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,5 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext;
|
|||
/// <typeparam name="TObject">The type of the object.</typeparam>
|
||||
/// <seealso cref="IMarkdownObjectRenderer" />
|
||||
public abstract class GemtextObjectRenderer<TObject>
|
||||
: MarkdownObjectRenderer<GemtextRenderer, TObject>
|
||||
where TObject : MarkdownObject
|
||||
{
|
||||
}
|
||||
: MarkdownObjectRenderer<GemtextRenderer, TObject>
|
||||
where TObject : MarkdownObject { }
|
||||
|
|
|
@ -8,22 +8,22 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
|||
/// <seealso cref="GemtextObjectRenderer{CodeInline}" />
|
||||
public class CodeInlineRenderer : GemtextObjectRenderer<CodeInline>
|
||||
{
|
||||
protected override void Write(GemtextRenderer renderer, CodeInline obj)
|
||||
{
|
||||
const string Delimiter = "`";
|
||||
InlineFormatting formatting = renderer.CodeFormattingResolved;
|
||||
bool normalize = formatting == InlineFormatting.Normalize;
|
||||
protected override void Write(GemtextRenderer renderer, CodeInline obj)
|
||||
{
|
||||
const string Delimiter = "`";
|
||||
InlineFormatting formatting = renderer.CodeFormattingResolved;
|
||||
bool normalize = formatting == InlineFormatting.Normalize;
|
||||
|
||||
if (normalize)
|
||||
{
|
||||
renderer.Write(Delimiter);
|
||||
}
|
||||
if (normalize)
|
||||
{
|
||||
renderer.Write(Delimiter);
|
||||
}
|
||||
|
||||
renderer.Write(obj.Content);
|
||||
renderer.Write(obj.Content);
|
||||
|
||||
if (normalize)
|
||||
{
|
||||
renderer.Write(Delimiter);
|
||||
}
|
||||
}
|
||||
if (normalize)
|
||||
{
|
||||
renderer.Write(Delimiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,11 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
|||
/// A Gemtext renderer for a <see cref="DelimiterInline" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="GemtextObjectRenderer{DelimiterInline}" />
|
||||
public class DelimiterInlineRenderer
|
||||
: GemtextObjectRenderer<DelimiterInline>
|
||||
public class DelimiterInlineRenderer : GemtextObjectRenderer<DelimiterInline>
|
||||
{
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
DelimiterInline obj)
|
||||
{
|
||||
renderer.Write(obj.ToLiteral());
|
||||
renderer.WriteChildren(obj);
|
||||
}
|
||||
protected override void Write(GemtextRenderer renderer, DelimiterInline obj)
|
||||
{
|
||||
renderer.Write(obj.ToLiteral());
|
||||
renderer.WriteChildren(obj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,24 +8,22 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
|||
/// <seealso cref="GemtextObjectRenderer{EmphasisInline}" />
|
||||
public class EmphasisInlineRenderer : GemtextObjectRenderer<EmphasisInline>
|
||||
{
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
EmphasisInline obj)
|
||||
{
|
||||
InlineFormatting formatting = renderer.EmphasisFormattingResolved;
|
||||
bool normalize = formatting == InlineFormatting.Normalize;
|
||||
string delimiter = new string('*', obj.DelimiterCount);
|
||||
protected override void Write(GemtextRenderer renderer, EmphasisInline obj)
|
||||
{
|
||||
InlineFormatting formatting = renderer.EmphasisFormattingResolved;
|
||||
bool normalize = formatting == InlineFormatting.Normalize;
|
||||
string delimiter = new string('*', obj.DelimiterCount);
|
||||
|
||||
if (normalize)
|
||||
{
|
||||
renderer.Write(delimiter);
|
||||
}
|
||||
if (normalize)
|
||||
{
|
||||
renderer.Write(delimiter);
|
||||
}
|
||||
|
||||
renderer.WriteChildren(obj);
|
||||
renderer.WriteChildren(obj);
|
||||
|
||||
if (normalize)
|
||||
{
|
||||
renderer.Write(delimiter);
|
||||
}
|
||||
}
|
||||
if (normalize)
|
||||
{
|
||||
renderer.Write(delimiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Net;
|
||||
|
||||
using Markdig.Extensions.SmartyPants;
|
||||
|
||||
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
||||
|
@ -8,33 +7,31 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
|||
/// A Gemtext renderer for a <see cref="SmartyPant" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="GemtextObjectRenderer{GemtextEntityInline}" />
|
||||
public class GemtextSmartyPantRenderer
|
||||
: GemtextObjectRenderer<SmartyPant>
|
||||
public class GemtextSmartyPantRenderer : GemtextObjectRenderer<SmartyPant>
|
||||
{
|
||||
private static readonly SmartyPantOptions DefaultOptions = new();
|
||||
private static readonly SmartyPantOptions DefaultOptions = new();
|
||||
|
||||
private readonly SmartyPantOptions options;
|
||||
private readonly SmartyPantOptions options;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HtmlSmartyPantRenderer" /> class.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public GemtextSmartyPantRenderer(SmartyPantOptions? options)
|
||||
{
|
||||
this.options = options
|
||||
?? throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HtmlSmartyPantRenderer" /> class.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public GemtextSmartyPantRenderer(SmartyPantOptions? options)
|
||||
{
|
||||
this.options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
protected override void Write(GemtextRenderer renderer, SmartyPant obj)
|
||||
{
|
||||
if (!this.options.Mapping.TryGetValue(obj.Type, out string? text))
|
||||
{
|
||||
DefaultOptions.Mapping.TryGetValue(obj.Type, out text);
|
||||
}
|
||||
protected override void Write(GemtextRenderer renderer, SmartyPant obj)
|
||||
{
|
||||
if (!this.options.Mapping.TryGetValue(obj.Type, out string? text))
|
||||
{
|
||||
DefaultOptions.Mapping.TryGetValue(obj.Type, out text);
|
||||
}
|
||||
|
||||
string? unicode = WebUtility.HtmlDecode(text);
|
||||
string? unicode = WebUtility.HtmlDecode(text);
|
||||
|
||||
renderer.Write(unicode);
|
||||
}
|
||||
renderer.Write(unicode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,10 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
|||
/// A Gemtext renderer for a <see cref="GemtextEntityInline" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="GemtextObjectRenderer{GemtextEntityInline}" />
|
||||
public class HtmlEntityInlineRenderer
|
||||
: GemtextObjectRenderer<HtmlEntityInline>
|
||||
public class HtmlEntityInlineRenderer : GemtextObjectRenderer<HtmlEntityInline>
|
||||
{
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
HtmlEntityInline obj)
|
||||
{
|
||||
renderer.Write(obj.Transcoded);
|
||||
}
|
||||
protected override void Write(GemtextRenderer renderer, HtmlEntityInline obj)
|
||||
{
|
||||
renderer.Write(obj.Transcoded);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,26 +6,23 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
|||
/// A Gemtext renderer for a <see cref="LineBreakInline" />.
|
||||
/// </summary>
|
||||
/// <seealso cref="GemtextObjectRenderer{LineBreakInline}" />
|
||||
public class LineBreakInlineRenderer
|
||||
: GemtextObjectRenderer<LineBreakInline>
|
||||
public class LineBreakInlineRenderer : GemtextObjectRenderer<LineBreakInline>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to render this softline break as a
|
||||
/// Gemtext hardline break tag (<br />)
|
||||
/// </summary>
|
||||
public bool RenderAsHardlineBreak { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to render this softline break as a
|
||||
/// Gemtext hardline break tag (<br />)
|
||||
/// </summary>
|
||||
public bool RenderAsHardlineBreak { get; set; }
|
||||
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
LineBreakInline obj)
|
||||
{
|
||||
if (obj.IsHard || this.RenderAsHardlineBreak)
|
||||
{
|
||||
renderer.EnsureTwoLines();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.Write(" ");
|
||||
}
|
||||
}
|
||||
protected override void Write(GemtextRenderer renderer, LineBreakInline obj)
|
||||
{
|
||||
if (obj.IsHard || this.RenderAsHardlineBreak)
|
||||
{
|
||||
renderer.EnsureTwoLines();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.Write(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,116 +8,110 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
|||
/// <seealso cref="GemtextObjectRenderer{LinkInline}" />
|
||||
public class LinkInlineRenderer : GemtextObjectRenderer<LinkInline>
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes out any gathered links in a block.
|
||||
/// </summary>
|
||||
/// <param name="renderer">The renderer being used.</param>
|
||||
public static void WriteGatheredLinks(GemtextRenderer renderer)
|
||||
{
|
||||
// If we have no gathered links, then there is nothing to do.
|
||||
if (renderer.GatheredLinks.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/// <summary>
|
||||
/// Writes out any gathered links in a block.
|
||||
/// </summary>
|
||||
/// <param name="renderer">The renderer being used.</param>
|
||||
public static void WriteGatheredLinks(GemtextRenderer renderer)
|
||||
{
|
||||
// If we have no gathered links, then there is nothing to do.
|
||||
if (renderer.GatheredLinks.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Put some space between the previous object and this one, then
|
||||
// write out each link which is already formatted.
|
||||
renderer.WriteLine();
|
||||
// Put some space between the previous object and this one, then
|
||||
// write out each link which is already formatted.
|
||||
renderer.WriteLine();
|
||||
|
||||
foreach (string? link in renderer.GatheredLinks)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
renderer.Write(link);
|
||||
}
|
||||
foreach (string? link in renderer.GatheredLinks)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
renderer.Write(link);
|
||||
}
|
||||
|
||||
// Clear out the list of links.
|
||||
renderer.GatheredLinks.Clear();
|
||||
}
|
||||
// Clear out the list of links.
|
||||
renderer.GatheredLinks.Clear();
|
||||
}
|
||||
|
||||
protected override void Write(GemtextRenderer renderer, LinkInline link)
|
||||
{
|
||||
// Figure out the various states we have.
|
||||
bool outside = !renderer.LinkInsideBlock;
|
||||
bool insert = !outside
|
||||
&& renderer.BlockLinkHandling ==
|
||||
BlockLinkHandling.InsertLine;
|
||||
bool gather = !outside
|
||||
&& renderer.BlockLinkHandling switch
|
||||
{
|
||||
BlockLinkHandling.DocumentEnd => true,
|
||||
BlockLinkHandling.ParagraphEnd => true,
|
||||
_ => false,
|
||||
};
|
||||
bool hasText = link.FirstChild != null;
|
||||
bool footnotes = renderer.EndLinkInlineFormatting
|
||||
== EndLinkInlineFormatting.Footnote;
|
||||
protected override void Write(GemtextRenderer renderer, LinkInline link)
|
||||
{
|
||||
// Figure out the various states we have.
|
||||
bool outside = !renderer.LinkInsideBlock;
|
||||
bool insert = !outside && renderer.BlockLinkHandling == BlockLinkHandling.InsertLine;
|
||||
bool gather =
|
||||
!outside
|
||||
&& renderer.BlockLinkHandling switch
|
||||
{
|
||||
BlockLinkHandling.DocumentEnd => true,
|
||||
BlockLinkHandling.ParagraphEnd => true,
|
||||
_ => false,
|
||||
};
|
||||
bool hasText = link.FirstChild != null;
|
||||
bool footnotes = renderer.EndLinkInlineFormatting == EndLinkInlineFormatting.Footnote;
|
||||
|
||||
// Bare links and ones where we insert into the paragraph have
|
||||
// their own line.
|
||||
string? url = link.GetDynamicUrl != null
|
||||
? link.GetDynamicUrl() ?? link.Url
|
||||
: link.Url;
|
||||
// Bare links and ones where we insert into the paragraph have
|
||||
// their own line.
|
||||
string? url = link.GetDynamicUrl != null ? link.GetDynamicUrl() ?? link.Url : link.Url;
|
||||
|
||||
if (outside || insert)
|
||||
{
|
||||
// Make sure we are at the beginning of the line before
|
||||
// rendering the link.
|
||||
renderer.EnsureLine();
|
||||
renderer.Write("=> ");
|
||||
renderer.Write(url);
|
||||
if (outside || insert)
|
||||
{
|
||||
// Make sure we are at the beginning of the line before
|
||||
// rendering the link.
|
||||
renderer.EnsureLine();
|
||||
renderer.Write("=> ");
|
||||
renderer.Write(url);
|
||||
|
||||
// If we have text, we need a space after the URL and before
|
||||
// the text.
|
||||
if (hasText)
|
||||
{
|
||||
renderer.Write(" ");
|
||||
}
|
||||
}
|
||||
// If we have text, we need a space after the URL and before
|
||||
// the text.
|
||||
if (hasText)
|
||||
{
|
||||
renderer.Write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
// Render the text for the link if we have it.
|
||||
if (hasText)
|
||||
{
|
||||
renderer.WriteChildren(link);
|
||||
}
|
||||
// Render the text for the link if we have it.
|
||||
if (hasText)
|
||||
{
|
||||
renderer.WriteChildren(link);
|
||||
}
|
||||
|
||||
// If we are gathering, then write out a footnote.
|
||||
if (gather)
|
||||
{
|
||||
int footnoteNumber = renderer.NextFootnoteNumber++;
|
||||
string linkText = footnotes
|
||||
? footnoteNumber + ": " + url
|
||||
: GetLinkText(link);
|
||||
// If we are gathering, then write out a footnote.
|
||||
if (gather)
|
||||
{
|
||||
int footnoteNumber = renderer.NextFootnoteNumber++;
|
||||
string linkText = footnotes ? footnoteNumber + ": " + url : GetLinkText(link);
|
||||
|
||||
if (footnotes)
|
||||
{
|
||||
renderer.Write($"[{footnoteNumber}]");
|
||||
}
|
||||
if (footnotes)
|
||||
{
|
||||
renderer.Write($"[{footnoteNumber}]");
|
||||
}
|
||||
|
||||
renderer.GatheredLinks.Add("=> " + url + " " + linkText);
|
||||
}
|
||||
renderer.GatheredLinks.Add("=> " + url + " " + linkText);
|
||||
}
|
||||
|
||||
// If we are inserting a line in the paragraph, we need a final
|
||||
// newline so the text of the paragraph continues on the next
|
||||
// line.
|
||||
if (insert)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
// If we are inserting a line in the paragraph, we need a final
|
||||
// newline so the text of the paragraph continues on the next
|
||||
// line.
|
||||
if (insert)
|
||||
{
|
||||
renderer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetLinkText(LinkInline link)
|
||||
{
|
||||
// This little bit of nasty code basically spins up a new renderer
|
||||
// to get the text of the link by itself. Then we return that
|
||||
// directly so it can be rendered as a link.
|
||||
StringWriter writer = new();
|
||||
GemtextRenderer renderer = new(writer);
|
||||
private static string GetLinkText(LinkInline link)
|
||||
{
|
||||
// This little bit of nasty code basically spins up a new renderer
|
||||
// to get the text of the link by itself. Then we return that
|
||||
// directly so it can be rendered as a link.
|
||||
StringWriter writer = new();
|
||||
GemtextRenderer renderer = new(writer);
|
||||
|
||||
renderer.WriteChildren(link);
|
||||
writer.Close();
|
||||
renderer.WriteChildren(link);
|
||||
writer.Close();
|
||||
|
||||
string text = writer.ToString();
|
||||
string text = writer.ToString();
|
||||
|
||||
return text;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,31 +8,29 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
|||
/// <seealso cref="GemtextObjectRenderer{LiteralInline}" />
|
||||
public class LiteralInlineRenderer : GemtextObjectRenderer<LiteralInline>
|
||||
{
|
||||
protected override void Write(
|
||||
GemtextRenderer renderer,
|
||||
LiteralInline obj)
|
||||
{
|
||||
// If we are inside a paragraph and we are doing inline formatting,
|
||||
// then we need to trim the text if we are before or after a link.
|
||||
string content = obj.Content.ToString();
|
||||
BlockLinkHandling handling = renderer.BlockLinkHandling;
|
||||
bool isInsert = handling == BlockLinkHandling.InsertLine;
|
||||
bool inBlock = renderer.LinkInsideBlock;
|
||||
protected override void Write(GemtextRenderer renderer, LiteralInline obj)
|
||||
{
|
||||
// If we are inside a paragraph and we are doing inline formatting,
|
||||
// then we need to trim the text if we are before or after a link.
|
||||
string content = obj.Content.ToString();
|
||||
BlockLinkHandling handling = renderer.BlockLinkHandling;
|
||||
bool isInsert = handling == BlockLinkHandling.InsertLine;
|
||||
bool inBlock = renderer.LinkInsideBlock;
|
||||
|
||||
if (inBlock && isInsert)
|
||||
{
|
||||
if (obj.PreviousSibling is LinkInline)
|
||||
{
|
||||
content = content.TrimStart();
|
||||
}
|
||||
if (inBlock && isInsert)
|
||||
{
|
||||
if (obj.PreviousSibling is LinkInline)
|
||||
{
|
||||
content = content.TrimStart();
|
||||
}
|
||||
|
||||
if (obj.NextSibling is LinkInline)
|
||||
{
|
||||
content = content.TrimEnd();
|
||||
}
|
||||
}
|
||||
if (obj.NextSibling is LinkInline)
|
||||
{
|
||||
content = content.TrimEnd();
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the manipulated content.
|
||||
renderer.Write(content);
|
||||
}
|
||||
// Write out the manipulated content.
|
||||
renderer.Write(content);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,27 +8,25 @@ namespace MfGames.Markdown.Gemtext.Renderers.Gemtext;
|
|||
/// </summary>
|
||||
public static class MarkdigExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if the paragraph only contains a link.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to inspect.</param>
|
||||
/// <returns>True if there is only a link in the paragraph.</returns>
|
||||
public static bool OnlyHasSingleLink(this ParagraphBlock obj)
|
||||
{
|
||||
return obj.Inline != null
|
||||
&& obj.Inline.Count() == 1
|
||||
&& obj.Inline.FirstChild is LinkInline;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines if the paragraph only contains a link.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to inspect.</param>
|
||||
/// <returns>True if there is only a link in the paragraph.</returns>
|
||||
public static bool OnlyHasSingleLink(this ParagraphBlock obj)
|
||||
{
|
||||
return obj.Inline != null && obj.Inline.Count() == 1 && obj.Inline.FirstChild is LinkInline;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the list item only contains a link.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to inspect.</param>
|
||||
/// <returns>True if there is only a link in the paragraph.</returns>
|
||||
public static bool OnlyHasSingleLink(this ListItemBlock obj)
|
||||
{
|
||||
return obj.Count == 1
|
||||
&& obj.LastChild is ParagraphBlock paragraphBlock
|
||||
&& paragraphBlock.OnlyHasSingleLink();
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines if the list item only contains a link.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to inspect.</param>
|
||||
/// <returns>True if there is only a link in the paragraph.</returns>
|
||||
public static bool OnlyHasSingleLink(this ListItemBlock obj)
|
||||
{
|
||||
return obj.Count == 1
|
||||
&& obj.LastChild is ParagraphBlock paragraphBlock
|
||||
&& paragraphBlock.OnlyHasSingleLink();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using Markdig.Helpers;
|
||||
using Markdig.Renderers;
|
||||
using Markdig.Syntax;
|
||||
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
|
||||
using MfGames.Markdown.Gemtext.Renderers.Gemtext.Inlines;
|
||||
|
||||
|
@ -9,175 +8,172 @@ namespace MfGames.Markdown.Gemtext.Renderers;
|
|||
|
||||
public class GemtextRenderer : TextRendererBase<GemtextRenderer>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public GemtextRenderer(TextWriter writer)
|
||||
: base(writer)
|
||||
{
|
||||
// Set up our default values.
|
||||
this.NextFootnoteNumber = 1;
|
||||
this.GatheredLinks = new List<string>();
|
||||
/// <inheritdoc />
|
||||
public GemtextRenderer(TextWriter writer)
|
||||
: base(writer)
|
||||
{
|
||||
// Set up our default values.
|
||||
this.NextFootnoteNumber = 1;
|
||||
this.GatheredLinks = new List<string>();
|
||||
|
||||
// Default block renderers.
|
||||
this.ObjectRenderers.Add(new CustomContainerRenderer());
|
||||
this.ObjectRenderers.Add(new CodeBlockRenderer());
|
||||
this.ObjectRenderers.Add(new HeadingRenderer());
|
||||
this.ObjectRenderers.Add(new HtmlBlockRenderer());
|
||||
this.ObjectRenderers.Add(new ListRenderer());
|
||||
this.ObjectRenderers.Add(new MarkdownDocumentRenderer());
|
||||
this.ObjectRenderers.Add(new ParagraphRenderer());
|
||||
this.ObjectRenderers.Add(new QuoteBlockRenderer());
|
||||
this.ObjectRenderers.Add(new ThematicBreakRenderer());
|
||||
// Default block renderers.
|
||||
this.ObjectRenderers.Add(new CustomContainerRenderer());
|
||||
this.ObjectRenderers.Add(new CodeBlockRenderer());
|
||||
this.ObjectRenderers.Add(new HeadingRenderer());
|
||||
this.ObjectRenderers.Add(new HtmlBlockRenderer());
|
||||
this.ObjectRenderers.Add(new ListRenderer());
|
||||
this.ObjectRenderers.Add(new MarkdownDocumentRenderer());
|
||||
this.ObjectRenderers.Add(new ParagraphRenderer());
|
||||
this.ObjectRenderers.Add(new QuoteBlockRenderer());
|
||||
this.ObjectRenderers.Add(new ThematicBreakRenderer());
|
||||
|
||||
// Default inline renderers.
|
||||
this.ObjectRenderers.Add(new CodeInlineRenderer());
|
||||
this.ObjectRenderers.Add(new DelimiterInlineRenderer());
|
||||
this.ObjectRenderers.Add(new EmphasisInlineRenderer());
|
||||
this.ObjectRenderers.Add(new HtmlEntityInlineRenderer());
|
||||
this.ObjectRenderers.Add(new LineBreakInlineRenderer());
|
||||
this.ObjectRenderers.Add(new LinkInlineRenderer());
|
||||
this.ObjectRenderers.Add(new LiteralInlineRenderer());
|
||||
}
|
||||
// Default inline renderers.
|
||||
this.ObjectRenderers.Add(new CodeInlineRenderer());
|
||||
this.ObjectRenderers.Add(new DelimiterInlineRenderer());
|
||||
this.ObjectRenderers.Add(new EmphasisInlineRenderer());
|
||||
this.ObjectRenderers.Add(new HtmlEntityInlineRenderer());
|
||||
this.ObjectRenderers.Add(new LineBreakInlineRenderer());
|
||||
this.ObjectRenderers.Add(new LinkInlineRenderer());
|
||||
this.ObjectRenderers.Add(new LiteralInlineRenderer());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how to handle links inside paragraphs and other blocks.
|
||||
/// </summary>
|
||||
public BlockLinkHandling BlockLinkHandling { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets how to handle links inside paragraphs and other blocks.
|
||||
/// </summary>
|
||||
public BlockLinkHandling BlockLinkHandling { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the optional formatting for code inlines (backticks).
|
||||
/// If this is unset, then `InlineFormatting` will be used.
|
||||
/// </summary>
|
||||
public InlineFormatting? CodeFormatting { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the optional formatting for code inlines (backticks).
|
||||
/// If this is unset, then `InlineFormatting` will be used.
|
||||
/// </summary>
|
||||
public InlineFormatting? CodeFormatting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actual formatting for code inlines (backticks) which
|
||||
/// is either `CodeInlineFormatting` or `InlineFormatting` if that
|
||||
/// is not set.
|
||||
/// </summary>
|
||||
public InlineFormatting CodeFormattingResolved =>
|
||||
this.CodeFormatting ?? this.InlineFormatting;
|
||||
/// <summary>
|
||||
/// Gets the actual formatting for code inlines (backticks) which
|
||||
/// is either `CodeInlineFormatting` or `InlineFormatting` if that
|
||||
/// is not set.
|
||||
/// </summary>
|
||||
public InlineFormatting CodeFormattingResolved => this.CodeFormatting ?? this.InlineFormatting;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the optional formatting for emphasis (which includes
|
||||
/// italics and bolds). If this is unset, then `InlineFormatting`
|
||||
/// will be used.
|
||||
/// </summary>
|
||||
public InlineFormatting? EmphasisFormatting { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the optional formatting for emphasis (which includes
|
||||
/// italics and bolds). If this is unset, then `InlineFormatting`
|
||||
/// will be used.
|
||||
/// </summary>
|
||||
public InlineFormatting? EmphasisFormatting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actual formatting for emphasis which is either
|
||||
/// `EmphasisFormatting` or `InlineFormatting` if that isn't set.
|
||||
/// </summary>
|
||||
public InlineFormatting EmphasisFormattingResolved =>
|
||||
this.EmphasisFormatting ?? this.InlineFormatting;
|
||||
/// <summary>
|
||||
/// Gets the actual formatting for emphasis which is either
|
||||
/// `EmphasisFormatting` or `InlineFormatting` if that isn't set.
|
||||
/// </summary>
|
||||
public InlineFormatting EmphasisFormattingResolved =>
|
||||
this.EmphasisFormatting ?? this.InlineFormatting;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the formatting for how links that are gathered at the
|
||||
/// end of a paragraph or document are formatted inside the paragraph.
|
||||
/// </summary>
|
||||
public EndLinkInlineFormatting EndLinkInlineFormatting { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the formatting for how links that are gathered at the
|
||||
/// end of a paragraph or document are formatted inside the paragraph.
|
||||
/// </summary>
|
||||
public EndLinkInlineFormatting EndLinkInlineFormatting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current list of formatted links that have been gathered
|
||||
/// up to this point for rendering.
|
||||
/// </summary>
|
||||
public List<string> GatheredLinks { get; }
|
||||
/// <summary>
|
||||
/// Gets the current list of formatted links that have been gathered
|
||||
/// up to this point for rendering.
|
||||
/// </summary>
|
||||
public List<string> GatheredLinks { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the formatting rule for HTML blocks.
|
||||
/// </summary>
|
||||
public HtmlBlockFormatting HtmlBlockFormatting { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the formatting rule for HTML blocks.
|
||||
/// </summary>
|
||||
public HtmlBlockFormatting HtmlBlockFormatting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default formatting for all inlines.
|
||||
/// </summary>
|
||||
public InlineFormatting InlineFormatting { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the default formatting for all inlines.
|
||||
/// </summary>
|
||||
public InlineFormatting InlineFormatting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An internal processing flag that determines if the rendered link
|
||||
/// is inside a block or not to trigger extra handling.
|
||||
/// </summary>
|
||||
public bool LinkInsideBlock { get; set; }
|
||||
/// <summary>
|
||||
/// An internal processing flag that determines if the rendered link
|
||||
/// is inside a block or not to trigger extra handling.
|
||||
/// </summary>
|
||||
public bool LinkInsideBlock { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the next footnote while rendering links.
|
||||
/// </summary>
|
||||
public int NextFootnoteNumber { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the next footnote while rendering links.
|
||||
/// </summary>
|
||||
public int NextFootnoteNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ensures there are two blank lines before an element.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public GemtextRenderer EnsureTwoLines()
|
||||
{
|
||||
if (this.previousWasLine)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
/// <summary>
|
||||
/// Ensures there are two blank lines before an element.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public GemtextRenderer EnsureTwoLines()
|
||||
{
|
||||
if (this.previousWasLine)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
this.WriteLine();
|
||||
this.WriteLine();
|
||||
this.WriteLine();
|
||||
this.WriteLine();
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A wrapper method to push the state of LinkInsideBlock while
|
||||
/// performing an action.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to perform.</param>
|
||||
public void WhileLinkInsideBlock(Action action)
|
||||
{
|
||||
bool oldState = this.LinkInsideBlock;
|
||||
this.LinkInsideBlock = true;
|
||||
action();
|
||||
this.LinkInsideBlock = oldState;
|
||||
}
|
||||
/// <summary>
|
||||
/// A wrapper method to push the state of LinkInsideBlock while
|
||||
/// performing an action.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to perform.</param>
|
||||
public void WhileLinkInsideBlock(Action action)
|
||||
{
|
||||
bool oldState = this.LinkInsideBlock;
|
||||
this.LinkInsideBlock = true;
|
||||
action();
|
||||
this.LinkInsideBlock = oldState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the lines of a <see cref="LeafBlock" />
|
||||
/// </summary>
|
||||
/// <param name="leafBlock">The leaf block.</param>
|
||||
/// <param name="writeEndOfLines">if set to <c>true</c> write end of lines.</param>
|
||||
/// <returns>This instance</returns>
|
||||
public GemtextRenderer WriteLeafRawLines(
|
||||
LeafBlock leafBlock,
|
||||
bool writeEndOfLines)
|
||||
{
|
||||
// Make sure we have sane input.
|
||||
if (leafBlock == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(leafBlock));
|
||||
}
|
||||
/// <summary>
|
||||
/// Writes the lines of a <see cref="LeafBlock" />
|
||||
/// </summary>
|
||||
/// <param name="leafBlock">The leaf block.</param>
|
||||
/// <param name="writeEndOfLines">if set to <c>true</c> write end of lines.</param>
|
||||
/// <returns>This instance</returns>
|
||||
public GemtextRenderer WriteLeafRawLines(LeafBlock leafBlock, bool writeEndOfLines)
|
||||
{
|
||||
// Make sure we have sane input.
|
||||
if (leafBlock == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(leafBlock));
|
||||
}
|
||||
|
||||
// If we have nothing to write, then don't do anything. Even though
|
||||
// Markdig says this can't be null, `leafBlock.Lines` may be null
|
||||
// according to the comments.
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
if (leafBlock.Lines.Lines == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
// If we have nothing to write, then don't do anything. Even though
|
||||
// Markdig says this can't be null, `leafBlock.Lines` may be null
|
||||
// according to the comments.
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
if (leafBlock.Lines.Lines == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
// Go through the block and write out each of the lines.
|
||||
StringLineGroup lines = leafBlock.Lines;
|
||||
StringLine[] slices = lines.Lines;
|
||||
// Go through the block and write out each of the lines.
|
||||
StringLineGroup lines = leafBlock.Lines;
|
||||
StringLine[] slices = lines.Lines;
|
||||
|
||||
for (int i = 0; i < lines.Count; i++)
|
||||
{
|
||||
if (!writeEndOfLines && i > 0)
|
||||
{
|
||||
this.WriteLine();
|
||||
}
|
||||
for (int i = 0; i < lines.Count; i++)
|
||||
{
|
||||
if (!writeEndOfLines && i > 0)
|
||||
{
|
||||
this.WriteLine();
|
||||
}
|
||||
|
||||
this.Write(ref slices[i].Slice);
|
||||
this.Write(ref slices[i].Slice);
|
||||
|
||||
if (writeEndOfLines)
|
||||
{
|
||||
this.WriteLine();
|
||||
}
|
||||
}
|
||||
if (writeEndOfLines)
|
||||
{
|
||||
this.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,14 @@ namespace MfGames.Markdown.Gemtext.Renderers;
|
|||
/// </summary>
|
||||
public enum HtmlBlockFormatting
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that HTML code blocks should just be removed.
|
||||
/// </summary>
|
||||
Remove,
|
||||
/// <summary>
|
||||
/// Indicates that HTML code blocks should just be removed.
|
||||
/// </summary>
|
||||
Remove,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that HTML code blocks should be treated as blocks with
|
||||
/// "html" as the type.
|
||||
/// </summary>
|
||||
CodeBlock,
|
||||
/// <summary>
|
||||
/// Indicates that HTML code blocks should be treated as blocks with
|
||||
/// "html" as the type.
|
||||
/// </summary>
|
||||
CodeBlock,
|
||||
}
|
||||
|
|
|
@ -6,15 +6,15 @@ namespace MfGames.Markdown.Gemtext.Renderers;
|
|||
/// </summary>
|
||||
public enum InlineFormatting
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that the inline should be remove and only the text
|
||||
/// rendered.
|
||||
/// </summary>
|
||||
Remove,
|
||||
/// <summary>
|
||||
/// Indicates that the inline should be remove and only the text
|
||||
/// rendered.
|
||||
/// </summary>
|
||||
Remove,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the inline should be left in place in a normalized
|
||||
/// form (such as converting `_italics_` into `*italics*`).
|
||||
/// </summary>
|
||||
Normalize,
|
||||
/// <summary>
|
||||
/// Indicates that the inline should be left in place in a normalized
|
||||
/// form (such as converting `_italics_` into `*italics*`).
|
||||
/// </summary>
|
||||
Normalize,
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ namespace MfGames.Markdown.Extensions;
|
|||
|
||||
public class WikiLink : LinkInline
|
||||
{
|
||||
public WikiLink()
|
||||
{
|
||||
this.IsClosed = false;
|
||||
}
|
||||
public WikiLink()
|
||||
{
|
||||
this.IsClosed = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,39 +9,34 @@ namespace MfGames.Markdown.Extensions;
|
|||
/// </summary>
|
||||
public class WikiLinkExtension : IMarkdownExtension
|
||||
{
|
||||
public WikiLinkExtension()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
public WikiLinkExtension()
|
||||
: this(null) { }
|
||||
|
||||
public WikiLinkExtension(WikiLinkOptions? options)
|
||||
{
|
||||
this.Options = options ?? new WikiLinkOptions();
|
||||
}
|
||||
public WikiLinkExtension(WikiLinkOptions? options)
|
||||
{
|
||||
this.Options = options ?? new WikiLinkOptions();
|
||||
}
|
||||
|
||||
public WikiLinkOptions Options { get; set; }
|
||||
public WikiLinkOptions Options { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
WikiLinkInlineParser? parser = pipeline.InlineParsers
|
||||
.FindExact<WikiLinkInlineParser>();
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
WikiLinkInlineParser? parser = pipeline.InlineParsers.FindExact<WikiLinkInlineParser>();
|
||||
|
||||
if (parser != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (parser != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
parser = new WikiLinkInlineParser(this.Options);
|
||||
pipeline.InlineParsers.InsertBefore<LinkInlineParser>(parser);
|
||||
}
|
||||
parser = new WikiLinkInlineParser(this.Options);
|
||||
pipeline.InlineParsers.InsertBefore<LinkInlineParser>(parser);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Setup(
|
||||
MarkdownPipeline pipeline,
|
||||
IMarkdownRenderer renderer)
|
||||
{
|
||||
// No setup needed here because we're using LinkInline which does the
|
||||
// bulk of the work.
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
// No setup needed here because we're using LinkInline which does the
|
||||
// bulk of the work.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,105 +6,98 @@ namespace MfGames.Markdown.Extensions;
|
|||
|
||||
public class WikiLinkInlineParser : InlineParser
|
||||
{
|
||||
private readonly WikiLinkOptions options;
|
||||
private readonly WikiLinkOptions options;
|
||||
|
||||
public WikiLinkInlineParser(WikiLinkOptions options)
|
||||
{
|
||||
this.options = options;
|
||||
this.OpeningCharacters = new[] { '[' };
|
||||
}
|
||||
public WikiLinkInlineParser(WikiLinkOptions options)
|
||||
{
|
||||
this.options = options;
|
||||
this.OpeningCharacters = new[] { '[' };
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Match(
|
||||
InlineProcessor processor,
|
||||
ref StringSlice slice)
|
||||
{
|
||||
// We are looking for the `[[` opening for the tag and that the first
|
||||
// one isn't escaped.
|
||||
if (IsNotDelimiter(slice, '['))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
// We are looking for the `[[` opening for the tag and that the first
|
||||
// one isn't escaped.
|
||||
if (IsNotDelimiter(slice, '['))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to loop over the entire link, including the `[[` and `]]`
|
||||
// while keeping track since we'll swallow additional characters beyond
|
||||
// the link.
|
||||
int linkStart = slice.Start;
|
||||
int linkEnd = slice.Start;
|
||||
// We need to loop over the entire link, including the `[[` and `]]`
|
||||
// while keeping track since we'll swallow additional characters beyond
|
||||
// the link.
|
||||
int linkStart = slice.Start;
|
||||
int linkEnd = slice.Start;
|
||||
|
||||
slice.Start += 2;
|
||||
slice.Start += 2;
|
||||
|
||||
// Our content starts after the double '[['.
|
||||
int contentStart = slice.Start;
|
||||
// Our content starts after the double '[['.
|
||||
int contentStart = slice.Start;
|
||||
|
||||
// We need to find the end of the link (the `]]`).
|
||||
while (IsNotDelimiter(slice, ']'))
|
||||
{
|
||||
slice.NextChar();
|
||||
linkEnd = slice.Start;
|
||||
}
|
||||
// We need to find the end of the link (the `]]`).
|
||||
while (IsNotDelimiter(slice, ']'))
|
||||
{
|
||||
slice.NextChar();
|
||||
linkEnd = slice.Start;
|
||||
}
|
||||
|
||||
// Pull out the components before we adjust for the ']]' for the end.
|
||||
int contentEnd = linkEnd;
|
||||
// Pull out the components before we adjust for the ']]' for the end.
|
||||
int contentEnd = linkEnd;
|
||||
|
||||
// Finish skipping over the `]]`.
|
||||
slice.NextChar();
|
||||
slice.NextChar();
|
||||
// Finish skipping over the `]]`.
|
||||
slice.NextChar();
|
||||
slice.NextChar();
|
||||
|
||||
// Format the label and the URL.
|
||||
string content = slice.Text.Substring(
|
||||
contentStart,
|
||||
contentEnd - contentStart);
|
||||
string[] contentParts = content.Split('|', 2);
|
||||
string label = contentParts.Last();
|
||||
string url = this.options.GetUrl(contentParts.First());
|
||||
// Format the label and the URL.
|
||||
string content = slice.Text.Substring(contentStart, contentEnd - contentStart);
|
||||
string[] contentParts = content.Split('|', 2);
|
||||
string label = contentParts.Last();
|
||||
string url = this.options.GetUrl(contentParts.First());
|
||||
|
||||
// Add in any trailing components. This merges the `'s` from
|
||||
// `[[Dale]]'s` into the label.
|
||||
while (this.options.IsTrailingLink(slice.CurrentChar))
|
||||
{
|
||||
label += slice.CurrentChar;
|
||||
slice.NextChar();
|
||||
linkEnd++;
|
||||
}
|
||||
// Add in any trailing components. This merges the `'s` from
|
||||
// `[[Dale]]'s` into the label.
|
||||
while (this.options.IsTrailingLink(slice.CurrentChar))
|
||||
{
|
||||
label += slice.CurrentChar;
|
||||
slice.NextChar();
|
||||
linkEnd++;
|
||||
}
|
||||
|
||||
// Create the link that we're replacing.
|
||||
WikiLink link = new()
|
||||
{
|
||||
Span =
|
||||
{
|
||||
Start = processor.GetSourcePosition(
|
||||
linkStart,
|
||||
out int line,
|
||||
out int column),
|
||||
},
|
||||
Line = line,
|
||||
Column = column,
|
||||
Url = url,
|
||||
IsClosed = true,
|
||||
};
|
||||
// Create the link that we're replacing.
|
||||
WikiLink link =
|
||||
new()
|
||||
{
|
||||
Span =
|
||||
{
|
||||
Start = processor.GetSourcePosition(linkStart, out int line, out int column),
|
||||
},
|
||||
Line = line,
|
||||
Column = column,
|
||||
Url = url,
|
||||
IsClosed = true,
|
||||
};
|
||||
|
||||
link.AppendChild(
|
||||
new LiteralInline()
|
||||
{
|
||||
Line = line,
|
||||
Column = column,
|
||||
Content = new StringSlice(label),
|
||||
IsClosed = true,
|
||||
});
|
||||
link.AppendChild(
|
||||
new LiteralInline()
|
||||
{
|
||||
Line = line,
|
||||
Column = column,
|
||||
Content = new StringSlice(label),
|
||||
IsClosed = true,
|
||||
}
|
||||
);
|
||||
|
||||
// Replace the inline and then indicate we have a match.
|
||||
processor.Inline = link;
|
||||
// Replace the inline and then indicate we have a match.
|
||||
processor.Inline = link;
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsNotDelimiter(
|
||||
StringSlice slice,
|
||||
char delimiter)
|
||||
{
|
||||
return slice.CurrentChar != delimiter
|
||||
|| slice.PeekChar() != delimiter
|
||||
|| slice.PeekCharExtra(-1) == '\\';
|
||||
}
|
||||
private static bool IsNotDelimiter(StringSlice slice, char delimiter)
|
||||
{
|
||||
return slice.CurrentChar != delimiter
|
||||
|| slice.PeekChar() != delimiter
|
||||
|| slice.PeekCharExtra(-1) == '\\';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,26 +4,26 @@ namespace MfGames.Markdown.Extensions;
|
|||
|
||||
public class WikiLinkOptions
|
||||
{
|
||||
public WikiLinkOptions()
|
||||
{
|
||||
this.GetUrl = a => a;
|
||||
this.IsTrailingLink = a => a.IsAlpha() || a == '\'';
|
||||
}
|
||||
public WikiLinkOptions()
|
||||
{
|
||||
this.GetUrl = a => a;
|
||||
this.IsTrailingLink = a => a.IsAlpha() || a == '\'';
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The callback to determine the link from the given wiki link. This does
|
||||
/// not include trailing additions or use the label (e.g., `(ab|cd)` would
|
||||
/// get `ab` as the parameters of this function.
|
||||
/// </summary>
|
||||
public Func<string, string> GetUrl { get; set; }
|
||||
/// <summary>
|
||||
/// The callback to determine the link from the given wiki link. This does
|
||||
/// not include trailing additions or use the label (e.g., `(ab|cd)` would
|
||||
/// get `ab` as the parameters of this function.
|
||||
/// </summary>
|
||||
public Func<string, string> GetUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// A callback to determine if the text after the link should be merged
|
||||
/// with the link label. This allows links such as [[Dale]]'s to be turned
|
||||
/// into "Dale's" but pointing to "Dale" as a page.
|
||||
/// </para>
|
||||
/// <para>The default is to include any character or the apostrophe.</para>
|
||||
/// </summary>
|
||||
public Func<char, bool> IsTrailingLink { get; set; }
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// A callback to determine if the text after the link should be merged
|
||||
/// with the link label. This allows links such as [[Dale]]'s to be turned
|
||||
/// into "Dale's" but pointing to "Dale" as a page.
|
||||
/// </para>
|
||||
/// <para>The default is to include any character or the apostrophe.</para>
|
||||
/// </summary>
|
||||
public Func<char, bool> IsTrailingLink { get; set; }
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ in [MarkDig](https://github.com/xoofx/markdig), an extensible library for conver
|
|||
|
||||
The library includes the following:
|
||||
|
||||
- An extension for converting wiki links, such as `[[MfGames]]` into a link based on the title. This is for both HTML
|
||||
and Gemtext.
|
||||
- A output library for using MarkDig to generate Gemtext for Gemini pods.
|
||||
- An extension for converting wiki links, such as `[[MfGames]]` into a link based on the title. This is for both HTML
|
||||
and Gemtext.
|
||||
- A output library for using MarkDig to generate Gemtext for Gemini pods.
|
||||
|
||||
The documentation is rather light at the moment, but the tests can show various ways of using the libraries.
|
||||
|
||||
|
@ -37,5 +37,5 @@ repository.
|
|||
|
||||
The two libraries are:
|
||||
|
||||
- MfGames.Markdown
|
||||
- MfGames.Markdown.Gemtext
|
||||
- MfGames.Markdown
|
||||
- MfGames.Markdown.Gemtext
|
||||
|
|
|
@ -4,15 +4,12 @@ namespace MfGames.Nitride.Calendar;
|
|||
|
||||
public class CreateCalendarValidator : AbstractValidator<CreateCalender>
|
||||
{
|
||||
public CreateCalendarValidator()
|
||||
{
|
||||
this.RuleFor(x => x.Path)
|
||||
.NotNull();
|
||||
public CreateCalendarValidator()
|
||||
{
|
||||
this.RuleFor(x => x.Path).NotNull();
|
||||
|
||||
this.RuleFor(x => x.GetEventSummary)
|
||||
.NotNull();
|
||||
this.RuleFor(x => x.GetEventSummary).NotNull();
|
||||
|
||||
this.RuleFor(x => x.GetEventUrl)
|
||||
.NotNull();
|
||||
}
|
||||
this.RuleFor(x => x.GetEventUrl).NotNull();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
using FluentValidation;
|
||||
|
||||
using Ical.Net.CalendarComponents;
|
||||
using Ical.Net.DataTypes;
|
||||
using Ical.Net.Serialization;
|
||||
|
||||
using MfGames.Gallium;
|
||||
using MfGames.Nitride.Contents;
|
||||
using MfGames.Nitride.Generators;
|
||||
using MfGames.Nitride.Temporal;
|
||||
|
||||
using NodaTime;
|
||||
|
||||
using Zio;
|
||||
|
||||
namespace MfGames.Nitride.Calendar;
|
||||
|
@ -23,91 +19,88 @@ namespace MfGames.Nitride.Calendar;
|
|||
[WithProperties]
|
||||
public partial class CreateCalender : OperationBase
|
||||
{
|
||||
private readonly TimeService clock;
|
||||
private readonly TimeService clock;
|
||||
|
||||
private readonly IValidator<CreateCalender> validator;
|
||||
private readonly IValidator<CreateCalender> validator;
|
||||
|
||||
public CreateCalender(
|
||||
IValidator<CreateCalender> validator,
|
||||
TimeService clock)
|
||||
{
|
||||
this.validator = validator;
|
||||
this.clock = clock;
|
||||
}
|
||||
public CreateCalender(IValidator<CreateCalender> validator, TimeService clock)
|
||||
{
|
||||
this.validator = validator;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a callback to get the summary of the event representing
|
||||
/// the entity.
|
||||
/// </summary>
|
||||
public Func<Entity, string>? GetEventSummary { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a callback to get the summary of the event representing
|
||||
/// the entity.
|
||||
/// </summary>
|
||||
public Func<Entity, string>? GetEventSummary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a callback to get the optional URL of an event for
|
||||
/// the entity.
|
||||
/// </summary>
|
||||
public Func<Entity, Uri?>? GetEventUrl { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a callback to get the optional URL of an event for
|
||||
/// the entity.
|
||||
/// </summary>
|
||||
public Func<Entity, Uri?>? GetEventUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file system path for the resulting calendar.
|
||||
/// </summary>
|
||||
public UPath? Path { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the file system path for the resulting calendar.
|
||||
/// </summary>
|
||||
public UPath? Path { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<Entity> Run(
|
||||
IEnumerable<Entity> input,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
this.validator.ValidateAndThrow(this);
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<Entity> Run(
|
||||
IEnumerable<Entity> input,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
this.validator.ValidateAndThrow(this);
|
||||
|
||||
SplitEntityEnumerations split = input.SplitEntity<Instant>();
|
||||
IEnumerable<Entity> datedAndCalendars =
|
||||
this.CreateCalendarEntity(split.HasAll);
|
||||
SplitEntityEnumerations split = input.SplitEntity<Instant>();
|
||||
IEnumerable<Entity> datedAndCalendars = this.CreateCalendarEntity(split.HasAll);
|
||||
|
||||
return datedAndCalendars.Union(split.NotHasAll);
|
||||
}
|
||||
return datedAndCalendars.Union(split.NotHasAll);
|
||||
}
|
||||
|
||||
private IEnumerable<Entity> CreateCalendarEntity(
|
||||
IEnumerable<Entity> entities)
|
||||
{
|
||||
// Create the calendar in the same time zone as the rest of the system.
|
||||
var calendar = new Ical.Net.Calendar();
|
||||
private IEnumerable<Entity> CreateCalendarEntity(IEnumerable<Entity> entities)
|
||||
{
|
||||
// Create the calendar in the same time zone as the rest of the system.
|
||||
var calendar = new Ical.Net.Calendar();
|
||||
|
||||
calendar.TimeZones.Add(new VTimeZone(this.clock.DateTimeZone.Id));
|
||||
calendar.TimeZones.Add(new VTimeZone(this.clock.DateTimeZone.Id));
|
||||
|
||||
// Go through the events and add all of them.
|
||||
var input = entities.ToList();
|
||||
IEnumerable<CalendarEvent> events =
|
||||
input.Select(this.CreateCalendarEvent);
|
||||
// Go through the events and add all of them.
|
||||
var input = entities.ToList();
|
||||
IEnumerable<CalendarEvent> events = input.Select(this.CreateCalendarEvent);
|
||||
|
||||
calendar.Events.AddRange(events);
|
||||
calendar.Events.AddRange(events);
|
||||
|
||||
// Create the iCalendar file.
|
||||
var serializer = new CalendarSerializer();
|
||||
string serializedCalendar = serializer.SerializeToString(calendar);
|
||||
// Create the iCalendar file.
|
||||
var serializer = new CalendarSerializer();
|
||||
string serializedCalendar = serializer.SerializeToString(calendar);
|
||||
|
||||
// Create the calendar entity and populate everything.
|
||||
Entity calendarEntity = new Entity().Set(IsCalendar.Instance)
|
||||
.Set(this.Path!.Value)
|
||||
.SetTextContent(serializedCalendar);
|
||||
// Create the calendar entity and populate everything.
|
||||
Entity calendarEntity = new Entity()
|
||||
.Set(IsCalendar.Instance)
|
||||
.Set(this.Path!.Value)
|
||||
.SetTextContent(serializedCalendar);
|
||||
|
||||
// Return the results along with the new calendar.
|
||||
return input.Union(new[] { calendarEntity });
|
||||
}
|
||||
// Return the results along with the new calendar.
|
||||
return input.Union(new[] { calendarEntity });
|
||||
}
|
||||
|
||||
private CalendarEvent CreateCalendarEvent(Entity entity)
|
||||
{
|
||||
Instant instant = entity.Get<Instant>();
|
||||
var when = this.clock.ToDateTime(instant);
|
||||
string summary = this.GetEventSummary!(entity);
|
||||
Uri? url = this.GetEventUrl?.Invoke(entity);
|
||||
private CalendarEvent CreateCalendarEvent(Entity entity)
|
||||
{
|
||||
Instant instant = entity.Get<Instant>();
|
||||
var when = this.clock.ToDateTime(instant);
|
||||
string summary = this.GetEventSummary!(entity);
|
||||
Uri? url = this.GetEventUrl?.Invoke(entity);
|
||||
|
||||
var calendarEvent = new CalendarEvent
|
||||
{
|
||||
Summary = summary,
|
||||
Start = new CalDateTime(when),
|
||||
Url = url,
|
||||
};
|
||||
var calendarEvent = new CalendarEvent
|
||||
{
|
||||
Summary = summary,
|
||||
Start = new CalDateTime(when),
|
||||
Url = url,
|
||||
};
|
||||
|
||||
return calendarEvent;
|
||||
}
|
||||
return calendarEvent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,4 @@ namespace MfGames.Nitride.Calendar;
|
|||
/// A marker component for identifying an entity that represents a calendar.
|
||||
/// </summary>
|
||||
[SingletonComponent]
|
||||
public partial class IsCalendar
|
||||
{
|
||||
}
|
||||
public partial class IsCalendar { }
|
||||
|
|
|
@ -1,26 +1,23 @@
|
|||
using Autofac;
|
||||
|
||||
using MfGames.Nitride.Temporal.Setup;
|
||||
|
||||
namespace MfGames.Nitride.Calendar;
|
||||
|
||||
public static class NitrideCalendarBuilderExtensions
|
||||
{
|
||||
private static bool loaded;
|
||||
private static bool loaded;
|
||||
|
||||
public static NitrideBuilder UseCalendar(this NitrideBuilder builder)
|
||||
{
|
||||
// If we've already loaded, then we have a problem.
|
||||
if (loaded)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Cannot use UseCalendar() more than once.");
|
||||
}
|
||||
public static NitrideBuilder UseCalendar(this NitrideBuilder builder)
|
||||
{
|
||||
// If we've already loaded, then we have a problem.
|
||||
if (loaded)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot use UseCalendar() more than once.");
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
loaded = true;
|
||||
|
||||
// Get the configuration so we can set the various options.
|
||||
return builder
|
||||
.ConfigureContainer(x => x.RegisterModule<NitrideCalendarModule>());
|
||||
}
|
||||
// Get the configuration so we can set the various options.
|
||||
return builder.ConfigureContainer(x => x.RegisterModule<NitrideCalendarModule>());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
using Autofac;
|
||||
|
||||
using MfGames.Nitride.Temporal.Setup;
|
||||
|
||||
namespace MfGames.Nitride.Calendar;
|
||||
|
||||
public class NitrideCalendarModule : Module
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterModule<NitrideTemporalModule>();
|
||||
builder.RegisterOperators(this);
|
||||
builder.RegisterValidators(this);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterModule<NitrideTemporalModule>();
|
||||
builder.RegisterOperators(this);
|
||||
builder.RegisterValidators(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
using CliWrap;
|
||||
using CliWrap.Buffered;
|
||||
|
||||
using FluentValidation;
|
||||
|
||||
using MfGames.Gallium;
|
||||
using MfGames.Nitride.Generators;
|
||||
|
||||
using Serilog;
|
||||
|
||||
// ReSharper disable ClassNeverInstantiated.Global
|
||||
|
@ -20,102 +16,97 @@ namespace MfGames.Nitride.Exec;
|
|||
[WithProperties]
|
||||
public partial class ExecOperation : AsyncOperationBase
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly ILogger logger;
|
||||
|
||||
private readonly IValidator<ExecOperation> validator;
|
||||
private readonly IValidator<ExecOperation> validator;
|
||||
|
||||
public ExecOperation(
|
||||
ILogger logger,
|
||||
IValidator<ExecOperation> validator)
|
||||
{
|
||||
this.logger = logger.ForContext<ExecOperation>();
|
||||
this.validator = validator;
|
||||
}
|
||||
public ExecOperation(ILogger logger, IValidator<ExecOperation> validator)
|
||||
{
|
||||
this.logger = logger.ForContext<ExecOperation>();
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the command associated with this operation.
|
||||
/// </summary>
|
||||
public Func<Command>? CreateCommand { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the command associated with this operation.
|
||||
/// </summary>
|
||||
public Func<Command>? CreateCommand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a callback to process the buffered output.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is mutually exclusive with OnResult.
|
||||
/// </remarks>
|
||||
public Func<BufferedCommandResult, IEnumerable<Entity>>? OnBufferedResult
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets a callback to process the buffered output.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is mutually exclusive with OnResult.
|
||||
/// </remarks>
|
||||
public Func<BufferedCommandResult, IEnumerable<Entity>>? OnBufferedResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a callback to process the output.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is mutually exclusive with OnBufferedResult.
|
||||
/// </remarks>
|
||||
public Func<CommandResult, IEnumerable<Entity>>? OnResult { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a callback to process the output.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is mutually exclusive with OnBufferedResult.
|
||||
/// </remarks>
|
||||
public Func<CommandResult, IEnumerable<Entity>>? OnResult { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async IAsyncEnumerable<Entity> RunAsync(
|
||||
IAsyncEnumerable<Entity> input,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Make sure everything is validated.
|
||||
await this.validator.ValidateAndThrowAsync(this, cancellationToken);
|
||||
/// <inheritdoc />
|
||||
public override async IAsyncEnumerable<Entity> RunAsync(
|
||||
IAsyncEnumerable<Entity> input,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// Make sure everything is validated.
|
||||
await this.validator.ValidateAndThrowAsync(this, cancellationToken);
|
||||
|
||||
// Drain the inputs.
|
||||
await foreach (Entity item in input.WithCancellation(cancellationToken))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
// Drain the inputs.
|
||||
await foreach (Entity item in input.WithCancellation(cancellationToken))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
|
||||
// Create the command from the input, then execute it as a buffered
|
||||
// output if we have a buffered result callback, otherwise as a command
|
||||
// result.
|
||||
Command command = this.CreateCommand!();
|
||||
// Create the command from the input, then execute it as a buffered
|
||||
// output if we have a buffered result callback, otherwise as a command
|
||||
// result.
|
||||
Command command = this.CreateCommand!();
|
||||
|
||||
if (this.OnBufferedResult != null)
|
||||
{
|
||||
BufferedCommandResult result = await command
|
||||
.ExecuteBufferedAsync(cancellationToken);
|
||||
if (this.OnBufferedResult != null)
|
||||
{
|
||||
BufferedCommandResult result = await command.ExecuteBufferedAsync(cancellationToken);
|
||||
|
||||
this.logger.Debug(
|
||||
"Execute buffered: {Command} {Arguments} = {ExitCode}",
|
||||
command.TargetFilePath,
|
||||
command.Arguments,
|
||||
result.ExitCode);
|
||||
this.logger.Debug(
|
||||
"Execute buffered: {Command} {Arguments} = {ExitCode}",
|
||||
command.TargetFilePath,
|
||||
command.Arguments,
|
||||
result.ExitCode
|
||||
);
|
||||
|
||||
IEnumerable<Entity> list = this.OnBufferedResult(result);
|
||||
IEnumerable<Entity> list = this.OnBufferedResult(result);
|
||||
|
||||
foreach (Entity item in list)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandResult result = await command
|
||||
.ExecuteAsync(cancellationToken);
|
||||
foreach (Entity item in list)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandResult result = await command.ExecuteAsync(cancellationToken);
|
||||
|
||||
this.logger.Debug(
|
||||
"Execute: {Command} {Arguments} = {ExitCode}",
|
||||
command.TargetFilePath,
|
||||
command.Arguments,
|
||||
result.ExitCode);
|
||||
this.logger.Debug(
|
||||
"Execute: {Command} {Arguments} = {ExitCode}",
|
||||
command.TargetFilePath,
|
||||
command.Arguments,
|
||||
result.ExitCode
|
||||
);
|
||||
|
||||
IEnumerable<Entity>? list = this.OnResult?.Invoke(result);
|
||||
IEnumerable<Entity>? list = this.OnResult?.Invoke(result);
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
if (list == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (Entity item in list)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Entity item in list)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,21 +2,19 @@ namespace MfGames.Nitride.Exec.Setup;
|
|||
|
||||
public static class NitrideExecBuilderExtensions
|
||||
{
|
||||
private static bool loaded;
|
||||
private static bool loaded;
|
||||
|
||||
public static NitrideBuilder UseExec(this NitrideBuilder builder)
|
||||
{
|
||||
// If we've already loaded, then we have a problem.
|
||||
if (loaded)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Cannot use UseExec() more than once.");
|
||||
}
|
||||
public static NitrideBuilder UseExec(this NitrideBuilder builder)
|
||||
{
|
||||
// If we've already loaded, then we have a problem.
|
||||
if (loaded)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot use UseExec() more than once.");
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
loaded = true;
|
||||
|
||||
// Get the configuration so we can set the various options.
|
||||
return builder
|
||||
.UseModule<NitrideExecModule>();
|
||||
}
|
||||
// Get the configuration so we can set the various options.
|
||||
return builder.UseModule<NitrideExecModule>();
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue