From d70d91e5591b83a689df0de40a40f07de0fda69b Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 7 Feb 2022 14:54:06 -0500 Subject: [PATCH] Remove old nushell/merge engine-q --- Cargo.lock | 2996 +---------------- Cargo.toml | 257 +- Cargo.toml.old | 229 ++ README.md | 4 - crates/README.md | 13 + crates/nu-ansi-term/.gitignore | 2 + crates/nu-ansi-term/Cargo.toml | 39 + crates/nu-ansi-term/LICENCE | 21 + crates/nu-ansi-term/README.md | 182 + crates/nu-ansi-term/examples/256_colors.rs | 72 + crates/nu-ansi-term/examples/basic_colors.rs | 18 + .../nu-ansi-term/examples/gradient_colors.rs | 37 + crates/nu-ansi-term/examples/rgb_colors.rs | 23 + crates/nu-ansi-term/src/ansi.rs | 405 +++ crates/nu-ansi-term/src/debug.rs | 152 + crates/nu-ansi-term/src/difference.rs | 174 + crates/nu-ansi-term/src/display.rs | 303 ++ crates/nu-ansi-term/src/gradient.rs | 105 + crates/nu-ansi-term/src/lib.rs | 272 ++ crates/nu-ansi-term/src/rgb.rs | 173 + crates/nu-ansi-term/src/style.rs | 626 ++++ crates/nu-ansi-term/src/util.rs | 80 + crates/nu-ansi-term/src/windows.rs | 62 + crates/nu-ansi-term/src/write.rs | 37 + crates/nu-cli/Cargo.toml | 58 +- crates/nu-cli/src/lib.rs | 18 - crates/nu-color-config/Cargo.toml | 11 +- crates/nu-command/Cargo.toml | 145 +- crates/nu-command/assets/228_themes.zip | Bin 0 -> 22290 bytes crates/nu-command/build.rs | 3 + crates/nu-command/src/default_context.rs | 374 -- crates/nu-command/src/filters/drop/nth.rs | 73 +- crates/nu-command/src/lib.rs | 30 - crates/nu-command/tests/commands/all.rs | 63 - crates/nu-command/tests/commands/any.rs | 37 - crates/nu-command/tests/commands/append.rs | 23 - crates/nu-command/tests/commands/cal.rs | 32 - crates/nu-command/tests/commands/cd.rs | 250 -- crates/nu-command/tests/commands/compact.rs | 50 + crates/nu-command/tests/commands/cp.rs | 6 - crates/nu-command/tests/commands/def.rs | 3 - crates/nu-command/tests/commands/default.rs | 35 + crates/nu-command/tests/commands/drop.rs | 16 +- crates/nu-command/tests/commands/each.rs | 24 - crates/nu-command/tests/commands/echo.rs | 20 - crates/nu-command/tests/commands/empty.rs | 12 - crates/nu-command/tests/commands/enter.rs | 15 - crates/nu-command/tests/commands/every.rs | 35 - crates/nu-command/tests/commands/find.rs | 16 - crates/nu-command/tests/commands/first.rs | 67 + crates/nu-command/tests/commands/flatten.rs | 12 - crates/nu-command/tests/commands/format.rs | 12 - crates/nu-command/tests/commands/get.rs | 9 - crates/nu-command/tests/commands/group_by.rs | 3 - crates/nu-command/tests/commands/hash_/mod.rs | 12 - crates/nu-command/tests/commands/headers.rs | 6 - crates/nu-command/tests/commands/help.rs | 3 - crates/nu-command/tests/commands/histogram.rs | 12 - .../tests/commands/into_filesize.rs | 31 - crates/nu-command/tests/commands/into_int.rs | 37 + crates/nu-command/tests/commands/keep/mod.rs | 3 + crates/nu-command/tests/commands/keep/rows.rs | 31 + .../nu-command/tests/commands/keep/until.rs | 15 - .../nu-command/tests/commands/keep/while_.rs | 14 - crates/nu-command/tests/commands/last.rs | 66 + crates/nu-command/tests/commands/length.rs | 25 + crates/nu-command/tests/commands/lines.rs | 8 - crates/nu-command/tests/commands/ls.rs | 19 - crates/nu-command/tests/commands/math/avg.rs | 7 - crates/nu-command/tests/commands/math/eval.rs | 12 - .../nu-command/tests/commands/math/median.rs | 40 + crates/nu-command/tests/commands/math/mod.rs | 31 - .../nu-command/tests/commands/math/round.rs | 21 + crates/nu-command/tests/commands/math/sqrt.rs | 6 - crates/nu-command/tests/commands/math/sum.rs | 3 - crates/nu-command/tests/commands/merge.rs | 3 - crates/nu-command/tests/commands/mkdir.rs | 84 + crates/nu-command/tests/commands/mod.rs | 15 - .../nu-command/tests/commands/move_/column.rs | 9 - crates/nu-command/tests/commands/move_/mod.rs | 2 + crates/nu-command/tests/commands/move_/mv.rs | 15 - crates/nu-command/tests/commands/nth.rs | 3 - crates/nu-command/tests/commands/open.rs | 26 - crates/nu-command/tests/commands/parse.rs | 6 - .../tests/commands/path/basename.rs | 83 + .../nu-command/tests/commands/path/dirname.rs | 137 + .../nu-command/tests/commands/path/exists.rs | 3 - .../nu-command/tests/commands/path/expand.rs | 78 + crates/nu-command/tests/commands/path/join.rs | 59 + crates/nu-command/tests/commands/path/mod.rs | 34 + .../nu-command/tests/commands/path/parse.rs | 3 - .../nu-command/tests/commands/path/split.rs | 7 - .../nu-command/tests/commands/path/type_.rs | 14 - crates/nu-command/tests/commands/prepend.rs | 29 + .../nu-command/tests/commands/random/bool.rs | 16 + .../nu-command/tests/commands/random/chars.rs | 14 + .../tests/commands/random/decimal.rs | 9 - .../nu-command/tests/commands/random/dice.rs | 13 + .../tests/commands/random/integer.rs | 3 - .../nu-command/tests/commands/random/mod.rs | 7 + .../nu-command/tests/commands/random/uuid.rs | 16 + crates/nu-command/tests/commands/range.rs | 68 + crates/nu-command/tests/commands/reduce.rs | 65 - crates/nu-command/tests/commands/rename.rs | 3 - crates/nu-command/tests/commands/reverse.rs | 11 + crates/nu-command/tests/commands/rm.rs | 12 - crates/nu-command/tests/commands/roll.rs | 22 - crates/nu-command/tests/commands/rotate.rs | 3 - crates/nu-command/tests/commands/save.rs | 3 - crates/nu-command/tests/commands/select.rs | 9 - crates/nu-command/tests/commands/semicolon.rs | 29 + crates/nu-command/tests/commands/skip/mod.rs | 2 + .../nu-command/tests/commands/skip/until.rs | 15 - .../nu-command/tests/commands/skip/while_.rs | 14 - crates/nu-command/tests/commands/sort_by.rs | 44 - crates/nu-command/tests/commands/source.rs | 36 - crates/nu-command/tests/commands/split_by.rs | 4 - .../nu-command/tests/commands/split_column.rs | 28 + crates/nu-command/tests/commands/split_row.rs | 28 + .../nu-command/tests/commands/str_/collect.rs | 8 - .../tests/commands/str_/into_string.rs | 158 + crates/nu-command/tests/commands/str_/mod.rs | 12 - crates/nu-command/tests/commands/touch.rs | 31 + crates/nu-command/tests/commands/uniq.rs | 24 - crates/nu-command/tests/commands/update.rs | 60 + crates/nu-command/tests/commands/where_.rs | 166 + crates/nu-command/tests/commands/which.rs | 96 + crates/nu-command/tests/commands/with_env.rs | 47 - crates/nu-command/tests/commands/wrap.rs | 61 + crates/nu-command/tests/commands/zip.rs | 38 - .../tests/format_conversions/bson.rs | 17 + .../tests/format_conversions/csv.rs | 12 - .../tests/format_conversions/eml.rs | 93 + .../tests/format_conversions/html.rs | 12 - .../tests/format_conversions/ics.rs | 9 - .../tests/format_conversions/json.rs | 100 + .../tests/format_conversions/markdown.rs | 98 + .../tests/format_conversions/mod.rs | 17 + .../tests/format_conversions/ods.rs | 4 - .../tests/format_conversions/sqlite.rs | 36 + .../tests/format_conversions/ssv.rs | 95 + .../tests/format_conversions/toml.rs | 16 + .../tests/format_conversions/tsv.rs | 132 + .../tests/format_conversions/url.rs | 16 + .../tests/format_conversions/vcf.rs | 4 - .../tests/format_conversions/xlsx.rs | 4 - .../tests/format_conversions/xml.rs | 4 - .../tests/format_conversions/yaml.rs | 16 + crates/nu-command/tests/main.rs | 16 - crates/nu-engine/Cargo.toml | 67 +- crates/nu-engine/src/documentation.rs | 261 -- crates/nu-engine/src/lib.rs | 43 - crates/nu-json/Cargo.toml | 16 +- crates/nu-json/LICENSE | 29 + crates/nu-json/src/builder.rs | 115 + crates/nu-json/src/de.rs | 833 +++++ crates/nu-json/src/error.rs | 166 + crates/nu-json/src/lib.rs | 4 - crates/nu-json/src/ser.rs | 38 - crates/nu-json/src/util.rs | 333 ++ crates/nu-json/src/value.rs | 1158 +++++++ crates/nu-json/tests/main.rs | 11 - crates/nu-parser/Cargo.toml | 34 +- crates/nu-parser/src/errors.rs | 21 - crates/nu-parser/src/lib.rs | 18 - crates/nu-path/Cargo.toml | 13 +- crates/nu-path/README.md | 3 + crates/nu-path/src/dots.rs | 4 - crates/nu-path/src/expansions.rs | 26 - crates/nu-path/src/lib.rs | 7 - crates/nu-path/src/tilde.rs | 20 - crates/nu-path/src/util.rs | 4 + crates/nu-path/tests/mod.rs | 1 + crates/nu-path/tests/util.rs | 45 + crates/nu-plugin/Cargo.toml | 30 +- crates/nu-plugin/src/lib.rs | 9 - crates/nu-pretty-hex/Cargo.lock | 201 ++ crates/nu-pretty-hex/Cargo.toml | 15 +- crates/nu-pretty-hex/LICENSE | 21 + crates/nu-pretty-hex/README.md | 81 + crates/nu-pretty-hex/src/lib.rs | 66 + crates/nu-pretty-hex/src/main.rs | 3 - crates/nu-pretty-hex/src/pretty_hex.rs | 17 - crates/nu-pretty-hex/tests/256.txt | 17 + crates/nu-pretty-hex/tests/data | 1 + crates/nu-pretty-hex/tests/tests.rs | 175 + crates/nu-protocol/Cargo.toml | 44 +- crates/nu-protocol/src/lib.rs | 38 - crates/nu-protocol/src/shell_error.rs | 2 +- crates/nu-protocol/src/signature.rs | 336 -- crates/nu-protocol/src/syntax_shape.rs | 70 - crates/nu-protocol/src/value/range.rs | 155 - crates/nu-system/Cargo.lock | 2 +- crates/nu-system/Cargo.toml | 2 +- crates/nu-table/.gitignore | 22 + crates/nu-table/Cargo.toml | 22 +- crates/nu-table/src/lib.rs | 5 + crates/nu-table/src/main.rs | 20 - crates/nu-table/src/table.rs | 101 - crates/nu-table/src/wrap.rs | 78 - crates/nu-term-grid/Cargo.toml | 2 +- crates/nu-test-support/Cargo.toml | 13 +- crates/nu-test-support/src/commands.rs | 49 - crates/nu-test-support/src/fs.rs | 277 ++ crates/nu-test-support/src/lib.rs | 12 - crates/nu-test-support/src/macros.rs | 39 - crates/nu-test-support/src/playground.rs | 12 + .../src/playground/director.rs | 27 - .../src/playground/matchers.rs | 105 + .../src/playground/nu_process.rs | 104 + crates/nu-test-support/src/playground/play.rs | 16 - .../nu-test-support/src/playground/tests.rs | 26 - crates/nu_plugin_chart/Cargo.toml | 21 + crates/nu_plugin_chart/src/bar.rs | 119 + .../src/bin/nu_plugin_chart_bar.rs | 6 + .../src/bin/nu_plugin_chart_line.rs | 6 + crates/nu_plugin_chart/src/lib.rs | 5 + crates/nu_plugin_chart/src/line.rs | 144 + crates/nu_plugin_chart/src/nu.rs | 5 + crates/nu_plugin_chart/src/nu/bar.rs | 371 ++ crates/nu_plugin_chart/src/nu/line.rs | 369 ++ crates/nu_plugin_example/Cargo.toml | 6 +- crates/nu_plugin_from_bson/Cargo.toml | 20 + crates/nu_plugin_from_bson/src/from_bson.rs | 212 ++ crates/nu_plugin_from_bson/src/lib.rs | 4 + crates/nu_plugin_from_bson/src/main.rs | 6 + crates/nu_plugin_from_bson/src/nu/mod.rs | 46 + crates/nu_plugin_from_bson/src/nu/tests.rs | 1 + crates/nu_plugin_from_mp4/Cargo.toml | 20 + crates/nu_plugin_from_mp4/src/from_mp4.rs | 174 + crates/nu_plugin_from_mp4/src/lib.rs | 4 + crates/nu_plugin_from_mp4/src/main.rs | 6 + crates/nu_plugin_from_mp4/src/nu/mod.rs | 46 + crates/nu_plugin_from_mp4/src/nu/tests.rs | 1 + crates/nu_plugin_from_sqlite/Cargo.toml | 24 + .../nu_plugin_from_sqlite/src/from_sqlite.rs | 138 + crates/nu_plugin_from_sqlite/src/lib.rs | 4 + crates/nu_plugin_from_sqlite/src/main.rs | 6 + crates/nu_plugin_from_sqlite/src/nu/mod.rs | 75 + crates/nu_plugin_from_sqlite/src/nu/tests.rs | 1 + crates/nu_plugin_gstat/Cargo.toml | 8 +- crates/nu_plugin_inc/Cargo.toml | 26 +- crates/nu_plugin_inc/src/inc.rs | 122 - crates/nu_plugin_inc/src/lib.rs | 34 - crates/nu_plugin_inc/src/main.rs | 8 - crates/nu_plugin_inc/src/nu/mod.rs | 74 - crates/nu_plugin_match/Cargo.toml | 18 + crates/nu_plugin_match/src/lib.rs | 4 + crates/nu_plugin_match/src/main.rs | 7 + crates/nu_plugin_match/src/match_.rs | 18 + crates/nu_plugin_match/src/nu/mod.rs | 124 + crates/nu_plugin_query/Cargo.toml | 8 +- crates/nu_plugin_s3/Cargo.toml | 20 + crates/nu_plugin_s3/README.md | 9 + crates/nu_plugin_s3/demo.png | Bin 0 -> 81084 bytes crates/nu_plugin_s3/src/handler.rs | 134 + crates/nu_plugin_s3/src/lib.rs | 4 + crates/nu_plugin_s3/src/main.rs | 6 + crates/nu_plugin_s3/src/nu/mod.rs | 60 + crates/nu_plugin_start/Cargo.toml | 26 + crates/nu_plugin_start/src/lib.rs | 4 + crates/nu_plugin_start/src/main.rs | 6 + crates/nu_plugin_start/src/nu/mod.rs | 28 + crates/nu_plugin_start/src/start.rs | 260 ++ crates/nu_plugin_to_bson/Cargo.toml | 23 + crates/nu_plugin_to_bson/src/lib.rs | 4 + crates/nu_plugin_to_bson/src/main.rs | 6 + crates/nu_plugin_to_bson/src/nu/mod.rs | 25 + crates/nu_plugin_to_bson/src/nu/tests.rs | 1 + crates/nu_plugin_to_bson/src/to_bson.rs | 300 ++ crates/nu_plugin_to_sqlite/Cargo.toml | 24 + crates/nu_plugin_to_sqlite/src/lib.rs | 4 + crates/nu_plugin_to_sqlite/src/main.rs | 6 + crates/nu_plugin_to_sqlite/src/nu/mod.rs | 25 + crates/nu_plugin_to_sqlite/src/nu/tests.rs | 1 + crates/nu_plugin_to_sqlite/src/to_sqlite.rs | 172 + crates/nu_plugin_tree/Cargo.toml | 20 + crates/nu_plugin_tree/src/lib.rs | 4 + crates/nu_plugin_tree/src/main.rs | 6 + crates/nu_plugin_tree/src/nu/mod.rs | 19 + crates/nu_plugin_tree/src/tree.rs | 80 + samples/wasm/Cargo.toml | 2 +- src/README.md | 5 + src/main.rs | 15 - src/plugins/nu_plugin_core_inc.rs | 8 - tests/assets/nu_json/charset_result.hjson | 5 + tests/assets/nu_json/charset_result.json | 5 + tests/assets/nu_json/charset_test.hjson | 6 + tests/assets/nu_json/comments_result.hjson | 26 + tests/assets/nu_json/comments_result.json | 26 + tests/assets/nu_json/comments_test.hjson | 48 + tests/assets/nu_json/empty_result.hjson | 3 + tests/assets/nu_json/empty_result.json | 3 + tests/assets/nu_json/empty_test.hjson | 3 + tests/assets/nu_json/failCharset1_test.hjson | 4 + tests/assets/nu_json/failJSON02_test.json | 1 + tests/assets/nu_json/failJSON05_test.json | 1 + tests/assets/nu_json/failJSON06_test.json | 1 + tests/assets/nu_json/failJSON07_test.json | 1 + tests/assets/nu_json/failJSON08_test.json | 1 + tests/assets/nu_json/failJSON10_test.json | 1 + tests/assets/nu_json/failJSON11_test.json | 1 + tests/assets/nu_json/failJSON12_test.json | 1 + tests/assets/nu_json/failJSON13_test.json | 1 + tests/assets/nu_json/failJSON14_test.json | 1 + tests/assets/nu_json/failJSON15_test.json | 1 + tests/assets/nu_json/failJSON16_test.json | 1 + tests/assets/nu_json/failJSON17_test.json | 1 + tests/assets/nu_json/failJSON19_test.json | 1 + tests/assets/nu_json/failJSON20_test.json | 1 + tests/assets/nu_json/failJSON21_test.json | 1 + tests/assets/nu_json/failJSON22_test.json | 1 + tests/assets/nu_json/failJSON23_test.json | 1 + tests/assets/nu_json/failJSON24_test.json | 1 + tests/assets/nu_json/failJSON26_test.json | 1 + tests/assets/nu_json/failJSON28_test.json | 2 + tests/assets/nu_json/failJSON29_test.json | 1 + tests/assets/nu_json/failJSON30_test.json | 1 + tests/assets/nu_json/failJSON31_test.json | 1 + tests/assets/nu_json/failJSON32_test.json | 1 + tests/assets/nu_json/failJSON33_test.json | 1 + tests/assets/nu_json/failJSON34_test.json | 2 + tests/assets/nu_json/failKey1_test.hjson | 4 + tests/assets/nu_json/failKey2_test.hjson | 4 + tests/assets/nu_json/failKey3_test.hjson | 4 + tests/assets/nu_json/failKey4_test.hjson | 4 + tests/assets/nu_json/failMLStr1_test.hjson | 3 + tests/assets/nu_json/failObj1_test.hjson | 6 + tests/assets/nu_json/failObj2_test.hjson | 6 + tests/assets/nu_json/failObj3_test.hjson | 7 + tests/assets/nu_json/failStr1a_test.hjson | 4 + tests/assets/nu_json/failStr1b_test.hjson | 4 + tests/assets/nu_json/failStr1c_test.hjson | 5 + tests/assets/nu_json/failStr1d_test.hjson | 5 + tests/assets/nu_json/failStr2a_test.hjson | 4 + tests/assets/nu_json/failStr2b_test.hjson | 4 + tests/assets/nu_json/failStr2c_test.hjson | 5 + tests/assets/nu_json/failStr2d_test.hjson | 5 + tests/assets/nu_json/failStr3a_test.hjson | 4 + tests/assets/nu_json/failStr3b_test.hjson | 4 + tests/assets/nu_json/failStr3c_test.hjson | 5 + tests/assets/nu_json/failStr3d_test.hjson | 5 + tests/assets/nu_json/failStr4a_test.hjson | 4 + tests/assets/nu_json/failStr4b_test.hjson | 4 + tests/assets/nu_json/failStr4c_test.hjson | 5 + tests/assets/nu_json/failStr4d_test.hjson | 5 + tests/assets/nu_json/failStr5a_test.hjson | 4 + tests/assets/nu_json/failStr5b_test.hjson | 4 + tests/assets/nu_json/failStr5c_test.hjson | 5 + tests/assets/nu_json/failStr5d_test.hjson | 5 + tests/assets/nu_json/failStr6a_test.hjson | 4 + tests/assets/nu_json/failStr6b_test.hjson | 4 + tests/assets/nu_json/failStr6c_test.hjson | 6 + tests/assets/nu_json/failStr6d_test.hjson | 6 + tests/assets/nu_json/kan_result.hjson | 48 + tests/assets/nu_json/kan_result.json | 45 + tests/assets/nu_json/kan_test.hjson | 49 + tests/assets/nu_json/keys_result.hjson | 34 + tests/assets/nu_json/keys_result.json | 34 + tests/assets/nu_json/keys_test.hjson | 48 + tests/assets/nu_json/oa_result.hjson | 13 + tests/assets/nu_json/oa_result.json | 13 + tests/assets/nu_json/oa_test.hjson | 13 + tests/assets/nu_json/pass1_result.hjson | 78 + tests/assets/nu_json/pass1_result.json | 75 + tests/assets/nu_json/pass1_test.json | 58 + tests/assets/nu_json/pass2_result.hjson | 39 + tests/assets/nu_json/pass2_result.json | 39 + tests/assets/nu_json/pass2_test.json | 1 + tests/assets/nu_json/pass3_result.hjson | 7 + tests/assets/nu_json/pass3_result.json | 6 + tests/assets/nu_json/pass3_test.json | 6 + tests/assets/nu_json/pass4_result.hjson | 1 + tests/assets/nu_json/pass4_result.json | 1 + tests/assets/nu_json/pass4_test.json | 2 + tests/assets/nu_json/passSingle_result.hjson | 1 + tests/assets/nu_json/passSingle_result.json | 1 + tests/assets/nu_json/passSingle_test.hjson | 1 + tests/assets/nu_json/root_result.hjson | 7 + tests/assets/nu_json/root_result.json | 6 + tests/assets/nu_json/root_test.hjson | 6 + tests/assets/nu_json/stringify1_result.hjson | 49 + tests/assets/nu_json/stringify1_result.json | 47 + tests/assets/nu_json/stringify1_test.hjson | 50 + tests/assets/nu_json/strings_result.hjson | 75 + tests/assets/nu_json/strings_result.json | 55 + tests/assets/nu_json/strings_test.hjson | 80 + tests/assets/nu_json/testlist.txt | 75 + tests/assets/nu_json/trail_result.hjson | 3 + tests/assets/nu_json/trail_result.json | 3 + tests/assets/nu_json/trail_test.hjson | 2 + tests/fixtures/formats/appveyor.yml | 31 + tests/fixtures/formats/caco3_plastics.csv | 10 + tests/fixtures/formats/caco3_plastics.tsv | 10 + tests/fixtures/formats/cargo_sample.toml | 55 + tests/fixtures/formats/jonathan.xml | 22 + tests/fixtures/formats/lines_test.txt | 2 + tests/fixtures/formats/random_numbers.csv | 51 + tests/fixtures/formats/sample-ls-output.json | 1 + tests/fixtures/formats/sample-ps-output.json | 1 + tests/fixtures/formats/sample-simple.json | 4 + tests/fixtures/formats/sample-sys-output.json | 125 + tests/fixtures/formats/sample.bson | Bin 0 -> 561 bytes tests/fixtures/formats/sample.db | Bin 0 -> 16384 bytes tests/fixtures/formats/sample.eml | 20 + tests/fixtures/formats/sample.ini | 19 + tests/fixtures/formats/sample.url | 1 + tests/fixtures/formats/sample_data.ods | Bin 0 -> 49626 bytes tests/fixtures/formats/sample_data.xlsx | Bin 0 -> 65801 bytes tests/fixtures/formats/sample_headers.xlsx | Bin 0 -> 4807 bytes tests/fixtures/formats/script.nu | 2 + tests/fixtures/formats/script_multiline.nu | 2 + tests/fixtures/formats/sgml_description.json | 30 + tests/fixtures/formats/utf16.ini | Bin 0 -> 504 bytes tests/fixtures/playground/config/default.toml | 3 + tests/fixtures/playground/config/startup.toml | 3 + tests/main.rs | 5 + tests/path/canonicalize.rs | 42 - tests/path/expand_path.rs | 90 - tests/path/mod.rs | 2 + tests/plugins/core_inc.rs | 135 + tests/plugins/mod.rs | 2 + tests/shell/environment/env.rs | 28 - tests/shell/environment/mod.rs | 6 - tests/shell/environment/nu_env.rs | 85 - tests/shell/mod.rs | 24 - tests/shell/pipeline/commands/external.rs | 81 - tests/shell/pipeline/commands/internal.rs | 422 --- tests/shell/pipeline/commands/mod.rs | 2 + tests/shell/pipeline/mod.rs | 10 + 430 files changed, 14543 insertions(+), 7865 deletions(-) create mode 100644 Cargo.toml.old create mode 100644 crates/README.md create mode 100644 crates/nu-ansi-term/.gitignore create mode 100644 crates/nu-ansi-term/Cargo.toml create mode 100644 crates/nu-ansi-term/LICENCE create mode 100644 crates/nu-ansi-term/README.md create mode 100644 crates/nu-ansi-term/examples/256_colors.rs create mode 100644 crates/nu-ansi-term/examples/basic_colors.rs create mode 100644 crates/nu-ansi-term/examples/gradient_colors.rs create mode 100644 crates/nu-ansi-term/examples/rgb_colors.rs create mode 100644 crates/nu-ansi-term/src/ansi.rs create mode 100644 crates/nu-ansi-term/src/debug.rs create mode 100644 crates/nu-ansi-term/src/difference.rs create mode 100644 crates/nu-ansi-term/src/display.rs create mode 100644 crates/nu-ansi-term/src/gradient.rs create mode 100644 crates/nu-ansi-term/src/lib.rs create mode 100644 crates/nu-ansi-term/src/rgb.rs create mode 100644 crates/nu-ansi-term/src/style.rs create mode 100644 crates/nu-ansi-term/src/util.rs create mode 100644 crates/nu-ansi-term/src/windows.rs create mode 100644 crates/nu-ansi-term/src/write.rs create mode 100644 crates/nu-command/assets/228_themes.zip create mode 100644 crates/nu-command/build.rs create mode 100644 crates/nu-command/tests/commands/compact.rs create mode 100644 crates/nu-command/tests/commands/default.rs create mode 100644 crates/nu-command/tests/commands/first.rs create mode 100644 crates/nu-command/tests/commands/into_int.rs create mode 100644 crates/nu-command/tests/commands/keep/mod.rs create mode 100644 crates/nu-command/tests/commands/keep/rows.rs create mode 100644 crates/nu-command/tests/commands/last.rs create mode 100644 crates/nu-command/tests/commands/length.rs create mode 100644 crates/nu-command/tests/commands/math/median.rs create mode 100644 crates/nu-command/tests/commands/math/round.rs create mode 100644 crates/nu-command/tests/commands/mkdir.rs create mode 100644 crates/nu-command/tests/commands/move_/mod.rs create mode 100644 crates/nu-command/tests/commands/path/basename.rs create mode 100644 crates/nu-command/tests/commands/path/dirname.rs create mode 100644 crates/nu-command/tests/commands/path/expand.rs create mode 100644 crates/nu-command/tests/commands/path/join.rs create mode 100644 crates/nu-command/tests/commands/path/mod.rs create mode 100644 crates/nu-command/tests/commands/prepend.rs create mode 100644 crates/nu-command/tests/commands/random/bool.rs create mode 100644 crates/nu-command/tests/commands/random/chars.rs create mode 100644 crates/nu-command/tests/commands/random/dice.rs create mode 100644 crates/nu-command/tests/commands/random/mod.rs create mode 100644 crates/nu-command/tests/commands/random/uuid.rs create mode 100644 crates/nu-command/tests/commands/range.rs create mode 100644 crates/nu-command/tests/commands/reverse.rs create mode 100644 crates/nu-command/tests/commands/semicolon.rs create mode 100644 crates/nu-command/tests/commands/skip/mod.rs create mode 100644 crates/nu-command/tests/commands/split_column.rs create mode 100644 crates/nu-command/tests/commands/split_row.rs create mode 100644 crates/nu-command/tests/commands/str_/into_string.rs create mode 100644 crates/nu-command/tests/commands/touch.rs create mode 100644 crates/nu-command/tests/commands/update.rs create mode 100644 crates/nu-command/tests/commands/where_.rs create mode 100644 crates/nu-command/tests/commands/which.rs create mode 100644 crates/nu-command/tests/commands/wrap.rs create mode 100644 crates/nu-command/tests/format_conversions/bson.rs create mode 100644 crates/nu-command/tests/format_conversions/eml.rs create mode 100644 crates/nu-command/tests/format_conversions/json.rs create mode 100644 crates/nu-command/tests/format_conversions/markdown.rs create mode 100644 crates/nu-command/tests/format_conversions/mod.rs create mode 100644 crates/nu-command/tests/format_conversions/sqlite.rs create mode 100644 crates/nu-command/tests/format_conversions/ssv.rs create mode 100644 crates/nu-command/tests/format_conversions/toml.rs create mode 100644 crates/nu-command/tests/format_conversions/tsv.rs create mode 100644 crates/nu-command/tests/format_conversions/url.rs create mode 100644 crates/nu-command/tests/format_conversions/yaml.rs create mode 100644 crates/nu-json/LICENSE create mode 100644 crates/nu-json/src/builder.rs create mode 100644 crates/nu-json/src/de.rs create mode 100644 crates/nu-json/src/error.rs create mode 100644 crates/nu-json/src/util.rs create mode 100644 crates/nu-json/src/value.rs create mode 100644 crates/nu-path/README.md create mode 100644 crates/nu-path/src/util.rs create mode 100644 crates/nu-path/tests/mod.rs create mode 100644 crates/nu-path/tests/util.rs create mode 100644 crates/nu-pretty-hex/Cargo.lock create mode 100644 crates/nu-pretty-hex/LICENSE create mode 100644 crates/nu-pretty-hex/README.md create mode 100644 crates/nu-pretty-hex/src/lib.rs create mode 100644 crates/nu-pretty-hex/tests/256.txt create mode 100644 crates/nu-pretty-hex/tests/data create mode 100644 crates/nu-pretty-hex/tests/tests.rs create mode 100644 crates/nu-table/.gitignore create mode 100644 crates/nu-table/src/lib.rs create mode 100644 crates/nu-test-support/src/fs.rs create mode 100644 crates/nu-test-support/src/playground.rs create mode 100644 crates/nu-test-support/src/playground/matchers.rs create mode 100644 crates/nu-test-support/src/playground/nu_process.rs create mode 100644 crates/nu_plugin_chart/Cargo.toml create mode 100644 crates/nu_plugin_chart/src/bar.rs create mode 100644 crates/nu_plugin_chart/src/bin/nu_plugin_chart_bar.rs create mode 100644 crates/nu_plugin_chart/src/bin/nu_plugin_chart_line.rs create mode 100644 crates/nu_plugin_chart/src/lib.rs create mode 100644 crates/nu_plugin_chart/src/line.rs create mode 100644 crates/nu_plugin_chart/src/nu.rs create mode 100644 crates/nu_plugin_chart/src/nu/bar.rs create mode 100644 crates/nu_plugin_chart/src/nu/line.rs create mode 100644 crates/nu_plugin_from_bson/Cargo.toml create mode 100644 crates/nu_plugin_from_bson/src/from_bson.rs create mode 100644 crates/nu_plugin_from_bson/src/lib.rs create mode 100644 crates/nu_plugin_from_bson/src/main.rs create mode 100644 crates/nu_plugin_from_bson/src/nu/mod.rs create mode 100644 crates/nu_plugin_from_bson/src/nu/tests.rs create mode 100644 crates/nu_plugin_from_mp4/Cargo.toml create mode 100644 crates/nu_plugin_from_mp4/src/from_mp4.rs create mode 100644 crates/nu_plugin_from_mp4/src/lib.rs create mode 100644 crates/nu_plugin_from_mp4/src/main.rs create mode 100644 crates/nu_plugin_from_mp4/src/nu/mod.rs create mode 100644 crates/nu_plugin_from_mp4/src/nu/tests.rs create mode 100644 crates/nu_plugin_from_sqlite/Cargo.toml create mode 100644 crates/nu_plugin_from_sqlite/src/from_sqlite.rs create mode 100644 crates/nu_plugin_from_sqlite/src/lib.rs create mode 100644 crates/nu_plugin_from_sqlite/src/main.rs create mode 100644 crates/nu_plugin_from_sqlite/src/nu/mod.rs create mode 100644 crates/nu_plugin_from_sqlite/src/nu/tests.rs create mode 100644 crates/nu_plugin_match/Cargo.toml create mode 100644 crates/nu_plugin_match/src/lib.rs create mode 100644 crates/nu_plugin_match/src/main.rs create mode 100644 crates/nu_plugin_match/src/match_.rs create mode 100644 crates/nu_plugin_match/src/nu/mod.rs create mode 100644 crates/nu_plugin_s3/Cargo.toml create mode 100644 crates/nu_plugin_s3/README.md create mode 100644 crates/nu_plugin_s3/demo.png create mode 100644 crates/nu_plugin_s3/src/handler.rs create mode 100644 crates/nu_plugin_s3/src/lib.rs create mode 100644 crates/nu_plugin_s3/src/main.rs create mode 100644 crates/nu_plugin_s3/src/nu/mod.rs create mode 100644 crates/nu_plugin_start/Cargo.toml create mode 100644 crates/nu_plugin_start/src/lib.rs create mode 100644 crates/nu_plugin_start/src/main.rs create mode 100644 crates/nu_plugin_start/src/nu/mod.rs create mode 100644 crates/nu_plugin_start/src/start.rs create mode 100644 crates/nu_plugin_to_bson/Cargo.toml create mode 100644 crates/nu_plugin_to_bson/src/lib.rs create mode 100644 crates/nu_plugin_to_bson/src/main.rs create mode 100644 crates/nu_plugin_to_bson/src/nu/mod.rs create mode 100644 crates/nu_plugin_to_bson/src/nu/tests.rs create mode 100644 crates/nu_plugin_to_bson/src/to_bson.rs create mode 100644 crates/nu_plugin_to_sqlite/Cargo.toml create mode 100644 crates/nu_plugin_to_sqlite/src/lib.rs create mode 100644 crates/nu_plugin_to_sqlite/src/main.rs create mode 100644 crates/nu_plugin_to_sqlite/src/nu/mod.rs create mode 100644 crates/nu_plugin_to_sqlite/src/nu/tests.rs create mode 100644 crates/nu_plugin_to_sqlite/src/to_sqlite.rs create mode 100644 crates/nu_plugin_tree/Cargo.toml create mode 100644 crates/nu_plugin_tree/src/lib.rs create mode 100644 crates/nu_plugin_tree/src/main.rs create mode 100644 crates/nu_plugin_tree/src/nu/mod.rs create mode 100644 crates/nu_plugin_tree/src/tree.rs create mode 100644 src/README.md create mode 100644 tests/assets/nu_json/charset_result.hjson create mode 100644 tests/assets/nu_json/charset_result.json create mode 100644 tests/assets/nu_json/charset_test.hjson create mode 100644 tests/assets/nu_json/comments_result.hjson create mode 100644 tests/assets/nu_json/comments_result.json create mode 100644 tests/assets/nu_json/comments_test.hjson create mode 100644 tests/assets/nu_json/empty_result.hjson create mode 100644 tests/assets/nu_json/empty_result.json create mode 100644 tests/assets/nu_json/empty_test.hjson create mode 100644 tests/assets/nu_json/failCharset1_test.hjson create mode 100644 tests/assets/nu_json/failJSON02_test.json create mode 100644 tests/assets/nu_json/failJSON05_test.json create mode 100644 tests/assets/nu_json/failJSON06_test.json create mode 100644 tests/assets/nu_json/failJSON07_test.json create mode 100644 tests/assets/nu_json/failJSON08_test.json create mode 100644 tests/assets/nu_json/failJSON10_test.json create mode 100644 tests/assets/nu_json/failJSON11_test.json create mode 100644 tests/assets/nu_json/failJSON12_test.json create mode 100644 tests/assets/nu_json/failJSON13_test.json create mode 100644 tests/assets/nu_json/failJSON14_test.json create mode 100644 tests/assets/nu_json/failJSON15_test.json create mode 100644 tests/assets/nu_json/failJSON16_test.json create mode 100644 tests/assets/nu_json/failJSON17_test.json create mode 100644 tests/assets/nu_json/failJSON19_test.json create mode 100644 tests/assets/nu_json/failJSON20_test.json create mode 100644 tests/assets/nu_json/failJSON21_test.json create mode 100644 tests/assets/nu_json/failJSON22_test.json create mode 100644 tests/assets/nu_json/failJSON23_test.json create mode 100644 tests/assets/nu_json/failJSON24_test.json create mode 100644 tests/assets/nu_json/failJSON26_test.json create mode 100644 tests/assets/nu_json/failJSON28_test.json create mode 100644 tests/assets/nu_json/failJSON29_test.json create mode 100644 tests/assets/nu_json/failJSON30_test.json create mode 100644 tests/assets/nu_json/failJSON31_test.json create mode 100644 tests/assets/nu_json/failJSON32_test.json create mode 100644 tests/assets/nu_json/failJSON33_test.json create mode 100644 tests/assets/nu_json/failJSON34_test.json create mode 100644 tests/assets/nu_json/failKey1_test.hjson create mode 100644 tests/assets/nu_json/failKey2_test.hjson create mode 100644 tests/assets/nu_json/failKey3_test.hjson create mode 100644 tests/assets/nu_json/failKey4_test.hjson create mode 100644 tests/assets/nu_json/failMLStr1_test.hjson create mode 100644 tests/assets/nu_json/failObj1_test.hjson create mode 100644 tests/assets/nu_json/failObj2_test.hjson create mode 100644 tests/assets/nu_json/failObj3_test.hjson create mode 100644 tests/assets/nu_json/failStr1a_test.hjson create mode 100644 tests/assets/nu_json/failStr1b_test.hjson create mode 100644 tests/assets/nu_json/failStr1c_test.hjson create mode 100644 tests/assets/nu_json/failStr1d_test.hjson create mode 100644 tests/assets/nu_json/failStr2a_test.hjson create mode 100644 tests/assets/nu_json/failStr2b_test.hjson create mode 100644 tests/assets/nu_json/failStr2c_test.hjson create mode 100644 tests/assets/nu_json/failStr2d_test.hjson create mode 100644 tests/assets/nu_json/failStr3a_test.hjson create mode 100644 tests/assets/nu_json/failStr3b_test.hjson create mode 100644 tests/assets/nu_json/failStr3c_test.hjson create mode 100644 tests/assets/nu_json/failStr3d_test.hjson create mode 100644 tests/assets/nu_json/failStr4a_test.hjson create mode 100644 tests/assets/nu_json/failStr4b_test.hjson create mode 100644 tests/assets/nu_json/failStr4c_test.hjson create mode 100644 tests/assets/nu_json/failStr4d_test.hjson create mode 100644 tests/assets/nu_json/failStr5a_test.hjson create mode 100644 tests/assets/nu_json/failStr5b_test.hjson create mode 100644 tests/assets/nu_json/failStr5c_test.hjson create mode 100644 tests/assets/nu_json/failStr5d_test.hjson create mode 100644 tests/assets/nu_json/failStr6a_test.hjson create mode 100644 tests/assets/nu_json/failStr6b_test.hjson create mode 100644 tests/assets/nu_json/failStr6c_test.hjson create mode 100644 tests/assets/nu_json/failStr6d_test.hjson create mode 100644 tests/assets/nu_json/kan_result.hjson create mode 100644 tests/assets/nu_json/kan_result.json create mode 100644 tests/assets/nu_json/kan_test.hjson create mode 100644 tests/assets/nu_json/keys_result.hjson create mode 100644 tests/assets/nu_json/keys_result.json create mode 100644 tests/assets/nu_json/keys_test.hjson create mode 100644 tests/assets/nu_json/oa_result.hjson create mode 100644 tests/assets/nu_json/oa_result.json create mode 100644 tests/assets/nu_json/oa_test.hjson create mode 100644 tests/assets/nu_json/pass1_result.hjson create mode 100644 tests/assets/nu_json/pass1_result.json create mode 100644 tests/assets/nu_json/pass1_test.json create mode 100644 tests/assets/nu_json/pass2_result.hjson create mode 100644 tests/assets/nu_json/pass2_result.json create mode 100644 tests/assets/nu_json/pass2_test.json create mode 100644 tests/assets/nu_json/pass3_result.hjson create mode 100644 tests/assets/nu_json/pass3_result.json create mode 100644 tests/assets/nu_json/pass3_test.json create mode 100644 tests/assets/nu_json/pass4_result.hjson create mode 100644 tests/assets/nu_json/pass4_result.json create mode 100644 tests/assets/nu_json/pass4_test.json create mode 100644 tests/assets/nu_json/passSingle_result.hjson create mode 100644 tests/assets/nu_json/passSingle_result.json create mode 100644 tests/assets/nu_json/passSingle_test.hjson create mode 100644 tests/assets/nu_json/root_result.hjson create mode 100644 tests/assets/nu_json/root_result.json create mode 100644 tests/assets/nu_json/root_test.hjson create mode 100644 tests/assets/nu_json/stringify1_result.hjson create mode 100644 tests/assets/nu_json/stringify1_result.json create mode 100644 tests/assets/nu_json/stringify1_test.hjson create mode 100644 tests/assets/nu_json/strings_result.hjson create mode 100644 tests/assets/nu_json/strings_result.json create mode 100644 tests/assets/nu_json/strings_test.hjson create mode 100644 tests/assets/nu_json/testlist.txt create mode 100644 tests/assets/nu_json/trail_result.hjson create mode 100644 tests/assets/nu_json/trail_result.json create mode 100644 tests/assets/nu_json/trail_test.hjson create mode 100644 tests/fixtures/formats/appveyor.yml create mode 100644 tests/fixtures/formats/caco3_plastics.csv create mode 100644 tests/fixtures/formats/caco3_plastics.tsv create mode 100644 tests/fixtures/formats/cargo_sample.toml create mode 100644 tests/fixtures/formats/jonathan.xml create mode 100644 tests/fixtures/formats/lines_test.txt create mode 100644 tests/fixtures/formats/random_numbers.csv create mode 100644 tests/fixtures/formats/sample-ls-output.json create mode 100644 tests/fixtures/formats/sample-ps-output.json create mode 100644 tests/fixtures/formats/sample-simple.json create mode 100644 tests/fixtures/formats/sample-sys-output.json create mode 100644 tests/fixtures/formats/sample.bson create mode 100644 tests/fixtures/formats/sample.db create mode 100644 tests/fixtures/formats/sample.eml create mode 100644 tests/fixtures/formats/sample.ini create mode 100644 tests/fixtures/formats/sample.url create mode 100644 tests/fixtures/formats/sample_data.ods create mode 100644 tests/fixtures/formats/sample_data.xlsx create mode 100644 tests/fixtures/formats/sample_headers.xlsx create mode 100755 tests/fixtures/formats/script.nu create mode 100644 tests/fixtures/formats/script_multiline.nu create mode 100644 tests/fixtures/formats/sgml_description.json create mode 100644 tests/fixtures/formats/utf16.ini create mode 100644 tests/fixtures/playground/config/default.toml create mode 100644 tests/fixtures/playground/config/startup.toml create mode 100644 tests/main.rs create mode 100644 tests/path/mod.rs create mode 100644 tests/plugins/core_inc.rs create mode 100644 tests/plugins/mod.rs create mode 100644 tests/shell/pipeline/commands/mod.rs create mode 100644 tests/shell/pipeline/mod.rs diff --git a/Cargo.lock b/Cargo.lock index ba99674365..e347004e19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,8 +3,6 @@ version = 3 [[package]] -<<<<<<< HEAD -======= name = "Inflector" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -15,7 +13,6 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "addr2line" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -31,29 +28,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -<<<<<<< HEAD -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "ahash" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ -<<<<<<< HEAD "getrandom 0.2.3", "once_cell", - "version_check", -======= - "getrandom 0.2.4", - "once_cell", - "version_check 0.9.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "version_check 0.9.3", ] [[package]] @@ -81,14 +63,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "ansi_colours" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e2fb6138a49ad9f1cb3c6d8f8ccbdd5e62b4dab317c1b435a47ecd7da1d28f" -dependencies = [ - "cc", -======= name = "ansi-cut" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -105,7 +79,6 @@ checksum = "bcb2392079bf27198570d6af79ecbd9ec7d8f16d3ec6b60933922fdb66287127" dependencies = [ "heapless 0.5.6", "nom 4.2.3", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -114,30 +87,20 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "anyhow" -<<<<<<< HEAD version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" -======= -version = "1.0.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" [[package]] name = "arrayref" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "arrayvec" @@ -165,27 +128,15 @@ dependencies = [ [[package]] name = "arrow2" -<<<<<<< HEAD -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d873e2775c3d87a4e8d77aa544cbd43f34a0779d5164c59e7c6a1dd0678eb395" -dependencies = [ - "ahash", -======= version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3452b2ae9727464a31a726c07ffec0c0da3b87831610d9ac99fc691c78b3a44" dependencies = [ ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "arrow-format", "base64", "chrono", "csv", -<<<<<<< HEAD - "futures 0.3.18", -======= "futures", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "hash_hasher", "indexmap", "lexical-core", @@ -200,8 +151,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -======= name = "as-slice" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -209,7 +158,7 @@ checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" dependencies = [ "generic-array 0.12.4", "generic-array 0.13.3", - "generic-array 0.14.5", + "generic-array 0.14.4", "stable_deref_trait", ] @@ -228,7 +177,6 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "async-stream" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -251,15 +199,9 @@ dependencies = [ [[package]] name = "async-trait" -<<<<<<< HEAD version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" -======= -version = "0.1.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "proc-macro2", "quote", @@ -274,11 +216,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -289,27 +227,15 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -<<<<<<< HEAD version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" -dependencies = [ - "addr2line", - "cc", - "cfg-if 1.0.0", - "libc", - "miniz_oxide 0.4.4", -======= -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" dependencies = [ "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "object", "rustc-demangle", ] @@ -321,35 +247,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] -<<<<<<< HEAD -name = "bat" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a069bad29696ecaa51ac79d3eb87abe3b65c7808ab2b3836afd9bd6c4009362" -dependencies = [ - "ansi_colours", - "ansi_term", - "bugreport", - "clircle", - "console", - "content_inspector", - "encoding", - "error-chain", - "git2", - "globset", - "grep-cli", - "path_abs", - "semver 0.11.0", - "serde", - "serde_yaml", - "shell-words", - "syntect", - "unicode-width", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "bigdecimal" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -362,21 +259,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -======= name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -390,7 +272,6 @@ checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" dependencies = [ "typenum", ] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "bitpacking" @@ -402,8 +283,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -======= name = "blake2b_simd" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -415,39 +294,28 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ -<<<<<<< HEAD - "generic-array", -======= - "generic-array 0.14.5", + "generic-array 0.14.4", ] [[package]] name = "block-buffer" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +checksum = "03588e54c62ae6d763e2a80090d50353b785795361b4ff5b3bf0a5097fc31c0b" dependencies = [ - "generic-array 0.14.5", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "generic-array 0.14.4", ] [[package]] name = "brotli" -<<<<<<< HEAD version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71cb90ade945043d3d53597b2fc359bb063db8ade2bcffe7997351d0756e9d50" -======= -version = "3.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f838e47a451d5a8fa552371f80024dd6ace9b7acdf25c4c3d0f9bc6816fb1c39" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -465,28 +333,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "bson" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff58d466782b57e0001c8e97c6a70c01c2359d7e13e257a83654c0b783ecc139" -dependencies = [ - "ahash", - "base64", - "chrono", - "hex", - "indexmap", - "lazy_static", - "rand 0.8.4", - "serde", - "serde_bytes", - "serde_json", - "uuid", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "bstr" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -498,29 +344,11 @@ dependencies = [ "serde", ] -[[package]] -<<<<<<< HEAD -name = "bugreport" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0014b4b2b4f63bfe69c3838470121290cc437fdc79785d408a761a21e8b2404c" -dependencies = [ - "git-version", - "shell-escape", - "sys-info", -] - [[package]] name = "bumpalo" version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" -======= -name = "bumpalo" -version = "3.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "byte-unit" @@ -532,15 +360,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "bytemuck" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -548,27 +367,6 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -<<<<<<< HEAD -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "iovec", -] - -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - -[[package]] -name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" -======= version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" @@ -578,7 +376,6 @@ name = "bytesize" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "bzip2" @@ -617,17 +414,10 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "cassowary" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" -======= name = "capnp" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16c262726f68118392269a3f7a5546baf51dcfe5cb3c3f0957b502106bf1a065" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "cc" @@ -640,15 +430,6 @@ dependencies = [ [[package]] name = "cfg-if" -<<<<<<< HEAD -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" @@ -663,13 +444,8 @@ dependencies = [ "num-integer", "num-traits", "serde", -<<<<<<< HEAD - "time 0.1.44", - "winapi 0.3.9", -======= "time", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -692,28 +468,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "clipboard-win" -version = "4.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8340083d28acb43451166543b98c838299b7e0863621be53a338adceea0ed" -dependencies = [ - "error-code", - "str-buf", - "winapi 0.3.9", -] - -[[package]] -name = "clircle" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e68bbd985a63de680ab4d1ad77b6306611a8f961b282c8b5ab513e6de934e396" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "serde", - "winapi 0.3.9", -======= name = "chrono-tz" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -733,7 +487,6 @@ dependencies = [ "parse-zoneinfo", "phf 0.10.1", "phf_codegen 0.10.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -746,54 +499,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "serde", - "termcolor", - "unicode-width", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - -[[package]] -name = "comfy-table" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a488ea8a8e295a53c7a4514b78a2e54bcff33adf99c15aced97b2a2062d4f8" -dependencies = [ - "crossterm", - "strum", - "strum_macros", -] - -[[package]] -name = "common-path" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" - -[[package]] -name = "console" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "regex", - "terminal_size", - "unicode-width", - "winapi 0.3.9", -======= name = "console" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -806,7 +511,6 @@ dependencies = [ "terminal_size", "unicode-width", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -816,20 +520,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb58b6451e8c2a812ad979ed1d83378caa5e927eef2622017a45f251457c2c9d" [[package]] -<<<<<<< HEAD -name = "content_inspector" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" -dependencies = [ - "memchr", -] -======= name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "convert_case" @@ -864,36 +558,20 @@ dependencies = [ [[package]] name = "crc32fast" -<<<<<<< HEAD version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" -dependencies = [ - "cfg-if 1.0.0", -======= -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3" dependencies = [ "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "crossbeam-channel" -<<<<<<< HEAD version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" -dependencies = [ - "cfg-if 1.0.0", -======= -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" dependencies = [ "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "crossbeam-utils", ] @@ -903,30 +581,18 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ -<<<<<<< HEAD - "cfg-if 1.0.0", -======= "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -<<<<<<< HEAD version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" -dependencies = [ - "cfg-if 1.0.0", -======= -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762" dependencies = [ "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "crossbeam-utils", "lazy_static", "memoffset", @@ -935,38 +601,16 @@ dependencies = [ [[package]] name = "crossbeam-utils" -<<<<<<< HEAD version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" -dependencies = [ - "cfg-if 1.0.0", -======= -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" dependencies = [ "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "lazy_static", ] [[package]] name = "crossterm" -<<<<<<< HEAD -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c36c10130df424b2f3552fcc2ddcd9b28a27b1e54b358b45874f88d1ca6888c" -dependencies = [ - "bitflags", - "crossterm_winapi", - "lazy_static", - "libc", - "mio", - "parking_lot", - "signal-hook", - "winapi 0.3.9", -======= version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c85525306c4291d1b73ce93c8acf9c339f9b213aef6c1d85c3830cbf1c16325c" @@ -980,24 +624,15 @@ dependencies = [ "signal-hook", "signal-hook-mio", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "crossterm_winapi" -<<<<<<< HEAD -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da8964ace4d3e4a044fd027919b2237000b24315a37c916f61809f1ff2140b9" -dependencies = [ - "winapi 0.3.9", -======= version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" dependencies = [ "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -1007,22 +642,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] -<<<<<<< HEAD -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -======= name = "crypto-common" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" dependencies = [ - "generic-array 0.14.5", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "generic-array 0.14.4", ] [[package]] @@ -1033,15 +658,9 @@ checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" dependencies = [ "cssparser-macros", "dtoa-short", -<<<<<<< HEAD "itoa", "matches", - "phf", -======= - "itoa 0.4.8", - "matches", "phf 0.8.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "proc-macro2", "quote", "smallvec", @@ -1060,15 +679,9 @@ dependencies = [ [[package]] name = "cstr_core" -<<<<<<< HEAD version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "917ba9efe9e1e736671d5a03f006afc4e7e3f32503e2077e0bcaf519c0c8c1d3" -======= -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644828c273c063ab0d39486ba42a5d1f3a499d35529c759e763a9c6cb8a0fb08" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "cty", "memchr", @@ -1082,11 +695,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", -<<<<<<< HEAD "itoa", -======= - "itoa 0.4.8", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "ryu", "serde", ] @@ -1101,15 +710,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "ctrlc" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377c9b002a72a0b2c1a18c62e2f3864bdfea4a015e3683a96e24aa45dd6c02d1" -dependencies = [ - "nix", - "winapi 0.3.9", -======= name = "ctor" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1127,7 +727,6 @@ checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf" dependencies = [ "nix", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -1137,25 +736,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] -<<<<<<< HEAD -name = "deflate" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" -dependencies = [ - "adler32", - "byteorder", -] - -[[package]] -name = "derive-new" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" -dependencies = [ - "proc-macro2", - "quote", -======= name = "derive_more" version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1165,26 +745,10 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "syn", ] [[package]] -<<<<<<< HEAD -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.0", - "syn", -] - -[[package]] -======= name = "dialoguer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1209,26 +773,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ -<<<<<<< HEAD - "generic-array", -] - -[[package]] -name = "directories-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" -dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", -======= - "generic-array 0.14.5", + "generic-array 0.14.4", ] [[package]] @@ -1237,19 +787,13 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" dependencies = [ - "block-buffer 0.10.0", + "block-buffer 0.10.1", "crypto-common", - "generic-array 0.14.5", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "generic-array 0.14.4", ] [[package]] name = "dirs" -<<<<<<< HEAD -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" -======= version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" @@ -1264,7 +808,6 @@ name = "dirs" version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "dirs-sys", ] @@ -1275,11 +818,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ -<<<<<<< HEAD - "cfg-if 1.0.0", -======= "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "dirs-sys-next", ] @@ -1290,13 +829,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ "libc", -<<<<<<< HEAD - "redox_users", - "winapi 0.3.9", -======= "redox_users 0.4.0", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -1306,13 +840,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", -<<<<<<< HEAD - "redox_users", - "winapi 0.3.9", -======= "redox_users 0.4.0", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -1343,11 +872,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13276c5dbd7f365e00efe6631242772fe6615e1899df84d1f6ce3ae7b48209f6" dependencies = [ "chrono", -<<<<<<< HEAD - "chrono-tz", -======= "chrono-tz 0.5.3", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "lazy_static", "num-traits", "rust_decimal", @@ -1360,15 +885,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" [[package]] -<<<<<<< HEAD -name = "dyn-clone" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "ego-tree" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1396,170 +912,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] -<<<<<<< HEAD -name = "encoding" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" -dependencies = [ - "encoding-index-japanese", - "encoding-index-korean", - "encoding-index-simpchinese", - "encoding-index-singlebyte", - "encoding-index-tradchinese", -] - -[[package]] -name = "encoding-index-japanese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-korean" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-simpchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-singlebyte" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-tradchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding_index_tests" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" - -[[package]] -name = "encoding_rs" -version = "0.8.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "endian-type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" - -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "env_logger" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", -] - -[[package]] -name = "error-code" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff" -dependencies = [ - "libc", - "str-buf", -] - -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - -[[package]] -name = "fd-lock" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc110fe50727d46a428eed832df40affe9bf74d077cac1bf3f2718e823f14c5" -dependencies = [ - "cfg-if 1.0.0", - "libc", -======= name = "encoding_rs" version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1627,15 +979,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - [[package]] name = "fd-lock" version = "3.0.3" @@ -1644,7 +987,6 @@ checksum = "fcef756dea9cf3db5ce73759cf0467330427a786b47711b8d6c97620d718ceb9" dependencies = [ "cfg-if", "rustix", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "windows-sys", ] @@ -1654,11 +996,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12d741e2415d4e2e5bd1c1d00409d1a8865a57892c2d689b504365655d237d43" dependencies = [ -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -1678,17 +1016,10 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ -<<<<<<< HEAD - "cfg-if 1.0.0", - "crc32fast", - "libc", - "miniz_oxide 0.4.4", -======= "cfg-if", "crc32fast", "libc", "miniz_oxide", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -1723,15 +1054,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "futf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1741,23 +1063,11 @@ dependencies = [ "new_debug_unreachable", ] -[[package]] -name = "futures" -<<<<<<< HEAD -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - [[package]] name = "futures" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" -======= -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "futures-channel", "futures-core", @@ -1770,15 +1080,9 @@ dependencies = [ [[package]] name = "futures-channel" -<<<<<<< HEAD version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" -======= -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "futures-core", "futures-sink", @@ -1786,7 +1090,6 @@ dependencies = [ [[package]] name = "futures-core" -<<<<<<< HEAD version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" @@ -1796,17 +1099,6 @@ name = "futures-executor" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" -======= -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" - -[[package]] -name = "futures-executor" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "futures-core", "futures-task", @@ -1815,7 +1107,6 @@ dependencies = [ [[package]] name = "futures-io" -<<<<<<< HEAD version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" @@ -1825,17 +1116,6 @@ name = "futures-macro" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" -======= -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" - -[[package]] -name = "futures-macro" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "proc-macro2", "quote", @@ -1844,7 +1124,6 @@ dependencies = [ [[package]] name = "futures-sink" -<<<<<<< HEAD version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" @@ -1861,25 +1140,6 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" dependencies = [ - "futures 0.1.31", -======= -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" - -[[package]] -name = "futures-task" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" - -[[package]] -name = "futures-util" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" -dependencies = [ ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "futures-channel", "futures-core", "futures-io", @@ -1890,10 +1150,6 @@ dependencies = [ "pin-project-lite", "pin-utils", "slab", -<<<<<<< HEAD - "tokio-io", -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -1907,14 +1163,6 @@ dependencies = [ [[package]] name = "generic-array" -<<<<<<< HEAD -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" -dependencies = [ - "typenum", - "version_check", -======= version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" @@ -1933,13 +1181,12 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", - "version_check 0.9.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "version_check 0.9.3", ] [[package]] @@ -1957,30 +1204,18 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ -<<<<<<< HEAD - "cfg-if 1.0.0", -======= "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -<<<<<<< HEAD version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" -dependencies = [ - "cfg-if 1.0.0", -======= -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "libc", "wasi 0.10.0+wasi-snapshot-preview1", ] @@ -1998,51 +1233,23 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "gimli" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" - -[[package]] -name = "git-version" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6b0decc02f4636b9ccad390dcbe77b722a77efedfa393caf8379a51d5c61899" -dependencies = [ - "git-version-macro", - "proc-macro-hack", -] - -[[package]] -name = "git-version-macro" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe69f1cbdb6e28af2bac214e943b99ce8a0a06b447d15d3e61161b0423139f3f" -dependencies = [ - "proc-macro-hack", -======= name = "ghost" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" dependencies = [ ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "proc-macro2", "quote", "syn", ] [[package]] -<<<<<<< HEAD -======= name = "gimli" version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "git2" version = "0.13.25" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2052,11 +1259,8 @@ dependencies = [ "libc", "libgit2-sys", "log", -<<<<<<< HEAD -======= "openssl-probe", "openssl-sys", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "url", ] @@ -2072,52 +1276,13 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -[[package]] -<<<<<<< HEAD -name = "globset" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "grep-cli" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd110c34bb4460d0de5062413b773e385cbf8a85a63fc535590110a09e79e8a" -dependencies = [ - "atty", - "bstr", - "globset", - "lazy_static", - "log", - "regex", - "same-file", - "termcolor", - "winapi-util", -] - [[package]] name = "h2" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" -dependencies = [ - "bytes 1.1.0", -======= -name = "h2" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" dependencies = [ "bytes", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "fnv", "futures-core", "futures-sink", @@ -2142,8 +1307,6 @@ dependencies = [ [[package]] name = "hash32" -<<<<<<< HEAD -======= version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" @@ -2153,7 +1316,6 @@ dependencies = [ [[package]] name = "hash32" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" @@ -2178,14 +1340,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "hashlink" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" -dependencies = [ - "hashbrown", -======= name = "heapless" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2195,24 +1349,15 @@ dependencies = [ "generic-array 0.13.3", "hash32 0.1.1", "stable_deref_trait", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "heapless" -<<<<<<< HEAD version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c1ad878e07405df82b695089e63d278244344f80e764074d0bdfe99b89460f3" -dependencies = [ - "hash32", -======= -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d076121838e03f862871315477528debffdb7462fb229216ecef91b1a3eb31eb" dependencies = [ "hash32 0.2.1", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "spin", "stable_deref_trait", ] @@ -2227,15 +1372,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2251,28 +1387,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -<<<<<<< HEAD -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest", -] - -[[package]] -name = "hmac-sha1" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1333fad8d94b82cab989da428b0b36a3435db3870d85e971a1d6dc0a8576722" -dependencies = [ - "sha1", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "html5ever" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2294,23 +1408,13 @@ checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" [[package]] name = "http" -<<<<<<< HEAD version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" -dependencies = [ - "bytes 1.1.0", - "fnv", - "itoa", -======= -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" dependencies = [ "bytes", "fnv", - "itoa 1.0.1", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "itoa", ] [[package]] @@ -2319,11 +1423,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" dependencies = [ -<<<<<<< HEAD - "bytes 1.1.0", -======= "bytes", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "http", "pin-project-lite", ] @@ -2351,19 +1451,11 @@ dependencies = [ [[package]] name = "hyper" -<<<<<<< HEAD version = "0.14.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c" -dependencies = [ - "bytes 1.1.0", -======= -version = "0.14.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" dependencies = [ "bytes", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "futures-channel", "futures-core", "futures-util", @@ -2372,11 +1464,7 @@ dependencies = [ "http-body", "httparse", "httpdate", -<<<<<<< HEAD "itoa", -======= - "itoa 0.4.8", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "pin-project-lite", "socket2", "tokio", @@ -2391,11 +1479,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ -<<<<<<< HEAD - "bytes 1.1.0", -======= "bytes", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "hyper", "native-tls", "tokio", @@ -2423,21 +1507,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "image" -version = "0.23.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "jpeg-decoder", - "num-iter", - "num-rational 0.3.2", - "num-traits", - "png", -======= name = "im" version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2448,21 +1517,14 @@ dependencies = [ "rand_xoshiro", "sized-chunks", "typenum", - "version_check 0.9.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "version_check 0.9.3", ] [[package]] name = "indexmap" -<<<<<<< HEAD version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" -======= -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "autocfg", "hashbrown", @@ -2470,34 +1532,12 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "insta" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15226a375927344c78d39dc6b49e2d5562a5b0705e26a589093c6792e52eed8e" -dependencies = [ - "console", - "lazy_static", - "serde", - "serde_json", - "serde_yaml", - "similar", - "uuid", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "instant" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ -<<<<<<< HEAD - "cfg-if 1.0.0", -======= "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -2511,14 +1551,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -======= name = "inventory" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2535,7 +1567,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ef6787e7f0faedc040f95716bdd0e62bcfcf4ba93da053b62dea2691c13864" dependencies = [ "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -2545,15 +1576,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] -<<<<<<< HEAD -======= name = "is_ci" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "is_debug" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2565,24 +1593,14 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" dependencies = [ -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "itertools" -<<<<<<< HEAD -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" -======= version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "either", ] @@ -2594,15 +1612,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] -<<<<<<< HEAD -======= -name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" - -[[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "jobserver" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2611,24 +1620,11 @@ dependencies = [ "libc", ] -[[package]] -<<<<<<< HEAD -name = "jpeg-decoder" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" - [[package]] name = "js-sys" version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" -======= -name = "js-sys" -version = "0.3.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "wasm-bindgen", ] @@ -2640,15 +1636,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -<<<<<<< HEAD -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "lexical" version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2723,15 +1710,9 @@ dependencies = [ [[package]] name = "libc" -<<<<<<< HEAD version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" -======= -version = "0.2.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "libgit2-sys" @@ -2741,13 +1722,9 @@ checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494" dependencies = [ "cc", "libc", -<<<<<<< HEAD - "libz-sys", -======= "libssh2-sys", "libz-sys", "openssl-sys", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "pkg-config", ] @@ -2758,14 +1735,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] -<<<<<<< HEAD -name = "libsqlite3-sys" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd5850c449b40bacb498b2bbdfaff648b1b055630073ba8db499caf2d0ea9f2" -dependencies = [ - "cc", -======= name = "libproc" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2785,7 +1754,6 @@ dependencies = [ "libc", "libz-sys", "openssl-sys", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "pkg-config", "vcpkg", ] @@ -2803,18 +1771,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "line-wrap" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "linked-hash-map" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2825,12 +1781,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "lock_api" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" -======= name = "linux-raw-sys" version = "0.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2838,10 +1788,9 @@ checksum = "95f5690fef754d905294c56f7ac815836f2513af966aa47f2e07ac79be07827f" [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -2852,9 +1801,6 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ -<<<<<<< HEAD - "cfg-if 1.0.0", -======= "cfg-if", ] @@ -2866,7 +1812,6 @@ checksum = "9dd58d8727f3035fa6d5272f16b519741fd4875936b99d8a7cde21291b7d9174" dependencies = [ "ansi_term", "crossterm", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -2911,13 +1856,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd" dependencies = [ "log", -<<<<<<< HEAD - "phf", - "phf_codegen", -======= "phf 0.8.0", "phf_codegen 0.8.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "string_cache", "string_cache_codegen", "tendril", @@ -2931,24 +1871,6 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "md-5" -<<<<<<< HEAD -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" -dependencies = [ - "block-buffer", - "digest", - "opaque-debug", -] - -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - -[[package]] -======= version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6a38fc55c8bbc10058782919516f88826e70320db6d206aebc49611d24216ae" @@ -2957,7 +1879,6 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "memchr" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2965,30 +1886,18 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memmap2" -<<<<<<< HEAD version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" -======= -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe3179b85e1fd8b14447cbebadb75e45a1002f541b925f0bfec366d56a81c56d" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "libc", ] [[package]] name = "memoffset" -<<<<<<< HEAD version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" -======= -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "autocfg", ] @@ -3000,35 +1909,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f79496a5651c8d57cd033c5add8ca7ee4e3d5f7587a4777484640d9cb60392d9" dependencies = [ "fnv", -<<<<<<< HEAD - "nom", -] - -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[package]] -name = "mime_guess" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] -======= "nom 1.2.4", ] @@ -3067,7 +1947,6 @@ name = "mime" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "miniz_oxide" @@ -3089,11 +1968,7 @@ dependencies = [ "log", "miow", "ntapi", -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -3102,25 +1977,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ -<<<<<<< HEAD - "winapi 0.3.9", -] - -[[package]] -name = "mp4" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85660d4d88b9318d95396943adc4a254b3ed8bf1de917e6f093abda1ccf0bec0" -dependencies = [ - "byteorder", - "bytes 0.5.6", - "num-rational 0.3.2", - "serde", - "serde_json", - "thiserror", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -3162,48 +2019,12 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "neso" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3c31defbcb081163db18437fd88c2a267cb3e26f7bd5e4b186e4b1b38fe8c8" -dependencies = [ - "bincode", - "cfg-if 0.1.10", - "log", - "serde", - "serde_derive", - "wasm-bindgen", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "new_debug_unreachable" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] -<<<<<<< HEAD -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - -[[package]] -name = "nix" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3bb9a13fa32bc5aeb64150cd3f32d6cf4c748f8f8a417cce5d2eb976a8370ba" -dependencies = [ - "bitflags", - "cc", - "cfg-if 1.0.0", -======= name = "nix" version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3212,7 +2033,6 @@ dependencies = [ "bitflags", "cc", "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "libc", "memoffset", ] @@ -3230,8 +2050,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce" [[package]] -<<<<<<< HEAD -======= name = "nom" version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3242,60 +2060,17 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "ntapi" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "nu" -<<<<<<< HEAD -version = "0.43.0" -dependencies = [ - "ctrlc", - "futures 0.3.18", - "hamcrest2", - "itertools", - "nu-cli", - "nu-command", - "nu-completion", - "nu-data", - "nu-engine", - "nu-errors", - "nu-parser", - "nu-path", - "nu-plugin", - "nu-protocol", - "nu-source", - "nu-test-support", - "nu-value-ext", - "nu_plugin_binaryview", - "nu_plugin_chart", - "nu_plugin_from_bson", - "nu_plugin_from_sqlite", - "nu_plugin_inc", - "nu_plugin_match", - "nu_plugin_query_json", - "nu_plugin_s3", - "nu_plugin_selector", - "nu_plugin_start", - "nu_plugin_textview", - "nu_plugin_to_bson", - "nu_plugin_to_sqlite", - "nu_plugin_tree", - "nu_plugin_xpath", - "rstest", - "serial_test", -======= -version = "0.1.0" +version = "0.59.0" dependencies = [ "assert_cmd", "crossterm", @@ -3330,58 +2105,21 @@ dependencies = [ "rstest", "serial_test", "tempfile", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "nu-ansi-term" -<<<<<<< HEAD -version = "0.43.0" -dependencies = [ - "doc-comment", - "overload", - "regex", - "serde", - "serde_json", - "winapi 0.3.9", -======= version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8afa9b5ba9e7ea9898e119244372cac911bea31ee7a5de42f51bbc36dc66318" dependencies = [ "overload", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "nu-cli" -<<<<<<< HEAD -version = "0.43.0" -dependencies = [ - "ctrlc", - "indexmap", - "lazy_static", - "log", - "nu-ansi-term", - "nu-command", - "nu-completion", - "nu-data", - "nu-engine", - "nu-errors", - "nu-parser", - "nu-path", - "nu-protocol", - "nu-source", - "nu-stream", - "pretty_env_logger", - "rustyline", - "serde", - "serde_yaml", - "shadow-rs", - "strip-ansi-escapes", -======= -version = "0.1.0" +version = "0.59.0" dependencies = [ "is_executable", "log", @@ -3398,33 +2136,18 @@ dependencies = [ [[package]] name = "nu-color-config" -version = "0.1.0" +version = "0.59.0" dependencies = [ "nu-ansi-term", "nu-json", "nu-protocol", "nu-table", "serde", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "nu-command" -<<<<<<< HEAD -version = "0.43.0" -dependencies = [ - "base64", - "bigdecimal", - "calamine", - "chrono", - "chrono-tz", - "crossterm", - "csv", - "ctrlc", - "derive-new", - "digest", -======= -version = "0.1.0" +version = "0.59.0" dependencies = [ "Inflector", "base64", @@ -3437,56 +2160,24 @@ dependencies = [ "csv", "dialoguer", "digest 0.10.1", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "dirs-next", "dtparse", "eml-parser", "encoding_rs", "filesize", -<<<<<<< HEAD - "futures 0.3.18", "glob", "hamcrest2", - "heck 0.4.0", -======= - "glob", - "hamcrest2", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "htmlescape", "ical", "indexmap", "itertools", "lazy_static", "log", -<<<<<<< HEAD -======= "lscolors", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "md-5", "meval", "mime", "nu-ansi-term", -<<<<<<< HEAD - "nu-data", - "nu-engine", - "nu-errors", - "nu-json", - "nu-parser", - "nu-path", - "nu-plugin", - "nu-pretty-hex", - "nu-protocol", - "nu-serde", - "nu-source", - "nu-stream", - "nu-table", - "nu-test-support", - "nu-value-ext", - "num-bigint 0.4.3", - "num-format", - "num-traits", - "parking_lot", -======= "nu-color-config", "nu-engine", "nu-json", @@ -3500,38 +2191,17 @@ dependencies = [ "nu-test-support", "num 0.4.0", "pathdiff", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "polars", "quick-xml 0.22.0", "quickcheck", "quickcheck_macros", "rand 0.8.4", -<<<<<<< HEAD -======= "rayon", "reedline", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "regex", "reqwest", "roxmltree", "rust-embed", -<<<<<<< HEAD - "rustyline", - "serde", - "serde_ini", - "serde_json", - "serde_urlencoded", - "serde_yaml", - "sha2", - "shadow-rs", - "strip-ansi-escapes", - "sysinfo", - "term", - "term_size", - "thiserror", - "titlecase", - "tokio", -======= "serde", "serde_ini", "serde_urlencoded", @@ -3543,7 +2213,6 @@ dependencies = [ "terminal_size", "thiserror", "titlecase", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "toml", "trash", "umask", @@ -3555,142 +2224,24 @@ dependencies = [ "zip", ] -[[package]] -<<<<<<< HEAD -name = "nu-completion" -version = "0.43.0" -dependencies = [ - "indexmap", - "is_executable", - "nu-data", - "nu-engine", - "nu-parser", - "nu-path", - "nu-protocol", - "nu-source", - "nu-test-support", - "parking_lot", -] - -[[package]] -name = "nu-data" -version = "0.43.0" -dependencies = [ - "bigdecimal", - "byte-unit", - "chrono", - "common-path", - "derive-new", - "directories-next", - "getset", - "indexmap", - "log", - "nu-ansi-term", - "nu-errors", - "nu-path", - "nu-protocol", - "nu-source", - "nu-table", - "nu-test-support", - "nu-value-ext", - "num-bigint 0.4.3", - "num-format", - "num-traits", - "serde", - "sha2", - "sys-locale", - "toml", -] - [[package]] name = "nu-engine" -version = "0.43.0" -dependencies = [ - "bigdecimal", - "bytes 1.1.0", - "chrono", - "codespan-reporting", - "derive-new", - "dirs-next", - "encoding_rs", - "filesize", - "fs_extra", - "getset", - "glob", - "hamcrest2", - "indexmap", - "itertools", - "lazy_static", - "log", - "nu-ansi-term", - "nu-data", - "nu-errors", - "nu-parser", - "nu-path", - "nu-plugin", - "nu-protocol", - "nu-source", - "nu-stream", - "nu-test-support", - "nu-value-ext", - "num-bigint 0.4.3", - "parking_lot", - "rayon", - "serde", - "serde_json", - "tempfile", - "term_size", - "termcolor", - "trash", - "umask", - "users", - "which", -] - -[[package]] -name = "nu-errors" -version = "0.43.0" -dependencies = [ - "bigdecimal", - "codespan-reporting", - "derive-new", - "getset", - "glob", - "nu-ansi-term", - "nu-source", - "num-bigint 0.4.3", - "num-traits", - "serde", - "serde_json", - "serde_yaml", - "toml", -======= -name = "nu-engine" -version = "0.1.0" +version = "0.59.0" dependencies = [ "chrono", "glob", "itertools", "nu-path", "nu-protocol", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "nu-json" -<<<<<<< HEAD -version = "0.43.0" -======= -version = "0.37.1" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +version = "0.59.0" dependencies = [ "lazy_static", "linked-hash-map", "nu-path", -<<<<<<< HEAD - "nu-test-support", -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "num-traits", "regex", "serde", @@ -3699,24 +2250,7 @@ dependencies = [ [[package]] name = "nu-parser" -<<<<<<< HEAD -version = "0.43.0" -dependencies = [ - "bigdecimal", - "derive-new", - "indexmap", - "itertools", - "log", - "nu-data", - "nu-errors", - "nu-path", - "nu-protocol", - "nu-source", - "nu-test-support", - "num-bigint 0.4.3", - "smart-default", -======= -version = "0.1.0" +version = "0.59.0" dependencies = [ "log", "miette", @@ -3725,16 +2259,11 @@ dependencies = [ "nu-protocol", "serde_json", "thiserror", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "nu-path" -<<<<<<< HEAD -version = "0.43.0" -======= -version = "0.37.1" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +version = "0.59.0" dependencies = [ "dirs-next", "dunce", @@ -3742,105 +2271,27 @@ dependencies = [ [[package]] name = "nu-plugin" -<<<<<<< HEAD -version = "0.43.0" -dependencies = [ - "indexmap", - "nu-errors", - "nu-protocol", - "nu-source", - "nu-test-support", - "nu-value-ext", -======= -version = "0.1.0" +version = "0.59.0" dependencies = [ "capnp", "nu-engine", "nu-protocol", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "serde", "serde_json", ] [[package]] name = "nu-pretty-hex" -<<<<<<< HEAD -version = "0.43.0" +version = "0.59.0" dependencies = [ - "heapless", -======= -version = "0.41.0" -dependencies = [ - "heapless 0.7.10", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "heapless 0.7.8", "nu-ansi-term", "rand 0.8.4", ] [[package]] name = "nu-protocol" -<<<<<<< HEAD -version = "0.43.0" -dependencies = [ - "bigdecimal", - "byte-unit", - "chrono", - "chrono-humanize", - "derive-new", - "getset", - "indexmap", - "log", - "nu-errors", - "nu-source", - "num-bigint 0.4.3", - "num-integer", - "num-traits", - "polars", - "serde", - "serde_bytes", -] - -[[package]] -name = "nu-serde" -version = "0.43.0" -dependencies = [ - "bigdecimal", - "insta", - "nu-protocol", - "nu-source", - "serde", - "thiserror", -] - -[[package]] -name = "nu-source" -version = "0.43.0" -dependencies = [ - "derive-new", - "getset", - "pretty", - "serde", - "termcolor", -] - -[[package]] -name = "nu-stream" -version = "0.43.0" -dependencies = [ - "nu-errors", - "nu-protocol", - "nu-source", -] - -[[package]] -name = "nu-table" -version = "0.43.0" -dependencies = [ - "atty", - "nu-ansi-term", - "regex", -======= -version = "0.1.0" +version = "0.59.0" dependencies = [ "byte-unit", "chrono", @@ -3859,7 +2310,7 @@ dependencies = [ [[package]] name = "nu-system" -version = "0.60.0" +version = "0.59.0" dependencies = [ "chrono", "errno", @@ -3875,7 +2326,7 @@ dependencies = [ [[package]] name = "nu-table" -version = "0.36.0" +version = "0.59.0" dependencies = [ "ansi-cut", "atty", @@ -3888,16 +2339,15 @@ dependencies = [ [[package]] name = "nu-term-grid" -version = "0.36.0" +version = "0.59.0" dependencies = [ ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "strip-ansi-escapes", "unicode-width", ] [[package]] name = "nu-test-support" -version = "0.43.0" +version = "0.59.0" dependencies = [ "bigdecimal", "chrono", @@ -3905,100 +2355,15 @@ dependencies = [ "glob", "hamcrest2", "indexmap", -<<<<<<< HEAD - "nu-errors", "nu-path", "nu-protocol", - "nu-source", -======= - "nu-path", - "nu-protocol", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "num-bigint 0.4.3", "tempfile", ] [[package]] -<<<<<<< HEAD -name = "nu-value-ext" -version = "0.43.0" -dependencies = [ - "indexmap", - "itertools", - "nu-errors", - "nu-protocol", - "nu-source", - "num-traits", -] - -[[package]] -name = "nu_plugin_binaryview" -version = "0.43.0" -dependencies = [ - "crossterm", - "image", - "neso", - "nu-ansi-term", - "nu-errors", - "nu-plugin", - "nu-pretty-hex", - "nu-protocol", - "nu-source", - "rawkey", -] - -[[package]] -name = "nu_plugin_chart" -version = "0.43.0" -dependencies = [ - "crossterm", - "nu-data", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "nu-value-ext", - "tui", -] - -[[package]] -name = "nu_plugin_from_bson" -version = "0.43.0" -dependencies = [ - "bigdecimal", - "bson", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", -] - -[[package]] -name = "nu_plugin_from_mp4" -version = "0.43.0" -dependencies = [ - "mp4", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "tempfile", -] - -[[package]] -name = "nu_plugin_from_sqlite" -version = "0.43.0" -dependencies = [ - "bigdecimal", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "rusqlite", - "tempfile", -======= name = "nu_plugin_example" -version = "0.1.0" +version = "0.59.0" dependencies = [ "nu-plugin", "nu-protocol", @@ -4006,166 +2371,32 @@ dependencies = [ [[package]] name = "nu_plugin_gstat" -version = "0.1.0" +version = "0.59.0" dependencies = [ "git2", "nu-engine", "nu-plugin", "nu-protocol", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "nu_plugin_inc" -<<<<<<< HEAD -version = "0.43.0" -dependencies = [ - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "nu-test-support", - "nu-value-ext", -======= -version = "0.1.0" +version = "0.59.0" dependencies = [ "nu-plugin", "nu-protocol", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "semver 0.11.0", ] [[package]] -<<<<<<< HEAD -name = "nu_plugin_match" -version = "0.43.0" -dependencies = [ - "nu-errors", - "nu-plugin", - "nu-protocol", - "regex", -] - -[[package]] -name = "nu_plugin_query_json" -version = "0.43.0" -dependencies = [ - "gjson", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", -] - -[[package]] -name = "nu_plugin_s3" -version = "0.43.0" -dependencies = [ - "futures 0.3.18", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "s3handler", -] - -[[package]] -name = "nu_plugin_selector" -version = "0.43.0" -dependencies = [ - "indexmap", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "scraper", -] - -[[package]] -name = "nu_plugin_start" -version = "0.43.0" -dependencies = [ - "glob", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "open", - "url", - "webbrowser", -] - -[[package]] -name = "nu_plugin_textview" -version = "0.43.0" -dependencies = [ - "bat", - "nu-data", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "term_size", - "url", -] - -[[package]] -name = "nu_plugin_to_bson" -version = "0.43.0" -dependencies = [ - "bson", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "num-traits", -] - -[[package]] -name = "nu_plugin_to_sqlite" -version = "0.43.0" -dependencies = [ - "hex", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "rusqlite", - "tempfile", -] - -[[package]] -name = "nu_plugin_tree" -version = "0.43.0" -dependencies = [ - "derive-new", - "nu-errors", - "nu-plugin", - "nu-protocol", - "ptree", -] - -[[package]] -name = "nu_plugin_xpath" -version = "0.43.0" -dependencies = [ - "bigdecimal", - "indexmap", - "nu-errors", - "nu-plugin", - "nu-protocol", - "nu-source", - "nu-test-support", -======= name = "nu_plugin_query" -version = "0.1.0" +version = "0.59.0" dependencies = [ "gjson", "nu-engine", "nu-plugin", "nu-protocol", "scraper", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "sxd-document", "sxd-xpath", ] @@ -4200,7 +2431,6 @@ dependencies = [ [[package]] name = "num-bigint" -<<<<<<< HEAD version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" @@ -4210,22 +2440,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" -======= -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -4264,12 +2478,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465" dependencies = [ "arrayvec 0.4.12", -<<<<<<< HEAD "itoa", - "num-bigint 0.2.6", -======= - "itoa 0.4.8", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -4307,22 +2516,6 @@ dependencies = [ [[package]] name = "num-rational" -<<<<<<< HEAD -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" -dependencies = [ - "autocfg", - "num-bigint 0.3.3", - "num-integer", - "num-traits", - "serde", -] - -[[package]] -name = "num-rational" -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" @@ -4345,15 +2538,9 @@ dependencies = [ [[package]] name = "num_cpus" -<<<<<<< HEAD version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -======= -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "hermit-abi", "libc", @@ -4379,38 +2566,10 @@ dependencies = [ [[package]] name = "once_cell" -<<<<<<< HEAD version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" -[[package]] -name = "onig" -version = "6.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ddfe2c93bb389eea6e6d713306880c7f6dcc99a75b659ce145d962c861b225" -dependencies = [ - "bitflags", - "lazy_static", - "libc", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd3eee045c84695b53b20255bb7317063df090b68e18bfac0abb6c39cf7f33e" -dependencies = [ - "cc", - "pkg-config", -] -======= -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce - [[package]] name = "opaque-debug" version = "0.3.0" @@ -4418,30 +2577,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] -<<<<<<< HEAD -name = "open" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcea7a30d6b81a2423cc59c43554880feff7b57d12916f231a79f8d6d9470201" -dependencies = [ - "pathdiff", - "winapi 0.3.9", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "openssl" version = "0.10.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" dependencies = [ "bitflags", -<<<<<<< HEAD - "cfg-if 1.0.0", -======= "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "foreign-types", "libc", "once_cell", @@ -4450,7 +2592,6 @@ dependencies = [ [[package]] name = "openssl-probe" -<<<<<<< HEAD version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" @@ -4460,17 +2601,6 @@ name = "openssl-sys" version = "0.9.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73" -======= -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "autocfg", "cc", @@ -4489,8 +2619,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -======= name = "output_vt100" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4500,22 +2628,18 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] -<<<<<<< HEAD -======= name = "owo-colors" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20448fd678ec04e6ea15bbe0476874af65e98a01515d667aa49f1434dc44ebf4" [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "parking_lot" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4532,21 +2656,12 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ -<<<<<<< HEAD - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi 0.3.9", -======= "cfg-if", "instant", "libc", "redox_syscall 0.2.10", "smallvec", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -4557,36 +2672,22 @@ checksum = "03abc2f9c83fe9ceec83f47c76cc071bfd56caba33794340330f35623ab1f544" dependencies = [ "async-trait", "byteorder", -<<<<<<< HEAD - "futures 0.3.18", -======= "futures", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "integer-encoding", "ordered-float", ] [[package]] name = "parquet2" -<<<<<<< HEAD -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db82df54cdd88931d29b850190915b9069bb93fba8e1aefc0d59d8ca81603d6d" -======= version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57e98d7da0076cead49c49580cc5771dfe0ba8a93cadff9b47c1681a4a78e1f9" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "async-stream", "bitpacking", "brotli", "flate2", -<<<<<<< HEAD - "futures 0.3.18", -======= "futures", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "lz4", "parquet-format-async-temp", "snap", @@ -4604,18 +2705,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "path_abs" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ef02f6342ac01d8a93b65f96db53fe68a92a15f41144f97fb00a9e669633c3" -dependencies = [ - "std_prelude", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "pathdiff" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4649,17 +2738,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" dependencies = [ "phf_macros", -<<<<<<< HEAD - "phf_shared", -======= "phf_shared 0.8.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "proc-macro-hack", ] [[package]] -<<<<<<< HEAD -======= name = "phf" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4669,16 +2752,11 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "phf_codegen" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" dependencies = [ -<<<<<<< HEAD - "phf_generator", - "phf_shared", -======= "phf_generator 0.8.0", "phf_shared 0.8.0", ] @@ -4691,7 +2769,6 @@ checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" dependencies = [ "phf_generator 0.10.0", "phf_shared 0.10.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -4700,17 +2777,11 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" dependencies = [ -<<<<<<< HEAD - "phf_shared", -======= "phf_shared 0.8.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "rand 0.7.3", ] [[package]] -<<<<<<< HEAD -======= name = "phf_generator" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4721,19 +2792,13 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "phf_macros" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" dependencies = [ -<<<<<<< HEAD - "phf_generator", - "phf_shared", -======= "phf_generator 0.8.0", "phf_shared 0.8.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "proc-macro-hack", "proc-macro2", "quote", @@ -4750,12 +2815,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "pin-project-lite" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" -======= name = "phf_shared" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4767,10 +2826,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] name = "pin-utils" @@ -4780,53 +2838,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -<<<<<<< HEAD version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" -[[package]] -name = "plist" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225" -dependencies = [ - "base64", - "indexmap", - "line-wrap", - "serde", - "time 0.3.5", - "xml-rs", -] - -[[package]] -name = "png" -version = "0.16.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" -dependencies = [ - "bitflags", - "crc32fast", - "deflate", - "miniz_oxide 0.3.7", -] - -[[package]] -name = "polars" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c94a25d46e93b64eac7848c028a545dc08fa01e148e4942c5442b3843c3a598" -======= -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" - [[package]] name = "polars" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e9211d1bb8d2d81541e4ab80ce9148a8e2a987d6412c2a48017fbbe24231ea1" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "polars-core", "polars-io", @@ -4835,15 +2855,9 @@ dependencies = [ [[package]] name = "polars-arrow" -<<<<<<< HEAD -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cc4488d2f2d6b901bb6e5728e58966013a272cae48861070b676215a79b4a99" -======= version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa5ee9c385bf6643893f98efa80ff5a07169b50f65962c7843c0a13e12f0b0cf" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "arrow2", "num 0.4.0", @@ -4852,36 +2866,22 @@ dependencies = [ [[package]] name = "polars-core" -<<<<<<< HEAD -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6771524063d742a08163d96875ca5df71dff7113f27da58db5ec5fa164165bf6" -======= version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cb1de44e479ce2764a7a3ad057e16f434efa334feb993284e1a48bb8888c6d1" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "ahash", "anyhow", "arrow2", "chrono", -<<<<<<< HEAD - "comfy-table", -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "hashbrown", "itertools", "lazy_static", "num 0.4.0", "num_cpus", "polars-arrow", -<<<<<<< HEAD - "rand 0.7.3", -======= "prettytable-rs", "rand 0.8.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "rand_distr", "rayon", "regex", @@ -4893,25 +2893,15 @@ dependencies = [ [[package]] name = "polars-io" -<<<<<<< HEAD -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a5f5f51525043ee7befd49e586e6919345237826a5f17b53956f8242100957" -======= version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bcb74f52ee9ff84863ae01de6ba25db092a9880302db4bf8f351f65b3ff0d12" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "ahash", "anyhow", "arrow2", "csv-core", -<<<<<<< HEAD - "dirs", -======= "dirs 4.0.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "lazy_static", "lexical", "memchr", @@ -4927,15 +2917,9 @@ dependencies = [ [[package]] name = "polars-lazy" -<<<<<<< HEAD -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3ea647e2fa59d1bbbf90929c5d10ef6a9018aac256d1c6d0e8248211804b61" -======= version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43f91022ba6463df71ad6eb80ac2307884578d9959e85e1fe9dac18988291d46" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "ahash", "itertools", @@ -4947,15 +2931,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -<<<<<<< HEAD version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" -======= -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "precomputed-hash" @@ -4964,14 +2942,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] -<<<<<<< HEAD -name = "pretty" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60c0d9f6fc88ecdd245d90c1920ff76a430ab34303fc778d33b1d0a4c3bf6d3" -dependencies = [ - "typed-arena", -======= name = "predicates" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5008,7 +2978,6 @@ dependencies = [ "ctor", "diff", "output_vt100", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -5022,8 +2991,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -======= name = "prettytable-rs" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5038,7 +3005,6 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5048,11 +3014,7 @@ dependencies = [ "proc-macro2", "quote", "syn", -<<<<<<< HEAD - "version_check", -======= - "version_check 0.9.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "version_check 0.9.3", ] [[package]] @@ -5063,11 +3025,7 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", -<<<<<<< HEAD - "version_check", -======= - "version_check 0.9.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "version_check 0.9.3", ] [[package]] @@ -5078,28 +3036,14 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -<<<<<<< HEAD version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" -======= -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "unicode-xid", ] [[package]] -<<<<<<< HEAD -name = "ptree" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0de80796b316aec75344095a6d2ef68ec9b8f573b9e7adc821149ba3598e270" -dependencies = [ - "serde", -======= name = "procfs" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5112,7 +3056,6 @@ dependencies = [ "hex", "lazy_static", "libc", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -5164,33 +3107,14 @@ dependencies = [ [[package]] name = "quote" -<<<<<<< HEAD version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" -======= -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "proc-macro2", ] [[package]] -<<<<<<< HEAD -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5251,30 +3175,17 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ -<<<<<<< HEAD "getrandom 0.2.3", -======= - "getrandom 0.2.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "rand_distr" -<<<<<<< HEAD -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9532ada3929fb8b2e9dbe28d1e06c9b2cc65813f074fcb6bd5fbefeff9d56" -dependencies = [ - "num-traits", - "rand 0.7.3", -======= version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", "rand 0.8.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -5305,24 +3216,12 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "rawkey" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ad6efac35ef044d565b23f0d111d76aa21ab2e86934b1225f7071d42e58ebad" -dependencies = [ - "readkey", - "user32-sys", - "winapi 0.3.9", - "x11", -======= name = "rand_xoshiro" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004" dependencies = [ "rand_core 0.5.1", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -5351,17 +3250,10 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "readkey" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d401b6d6a1725a59f1b4e813275d289dff3ad09c72b373a10a7a8217ba3146" -======= name = "redox_syscall" version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "redox_syscall" @@ -5374,8 +3266,6 @@ dependencies = [ [[package]] name = "redox_users" -<<<<<<< HEAD -======= version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" @@ -5387,16 +3277,11 @@ dependencies = [ [[package]] name = "redox_users" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ -<<<<<<< HEAD "getrandom 0.2.3", - "redox_syscall", -======= - "getrandom 0.2.4", "redox_syscall 0.2.10", ] @@ -5415,7 +3300,6 @@ dependencies = [ "strum_macros", "unicode-segmentation", "unicode-width", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -5447,37 +3331,20 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "reqwest" -<<<<<<< HEAD version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5" -dependencies = [ - "base64", - "bytes 1.1.0", - "encoding_rs", - "futures-core", - "futures-util", -======= -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "http", "http-body", "hyper", @@ -5519,16 +3386,6 @@ dependencies = [ [[package]] name = "rstest" -<<<<<<< HEAD -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "041bb0202c14f6a158bbbf086afb03d0c6e975c2dec7d4912f8061ed44f290af" -dependencies = [ - "cfg-if 1.0.0", - "proc-macro2", - "quote", - "rustc_version 0.3.3", -======= version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d912f35156a3f99a66ee3e11ac2e0b3f34ac85a07e05263d05a7e2c8810d616f" @@ -5537,25 +3394,10 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "syn", ] [[package]] -<<<<<<< HEAD -name = "rusqlite" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a82b0b91fad72160c56bf8da7a549b25d7c31109f52cc1437eac4c0ad2550a7" -dependencies = [ - "bitflags", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "memchr", - "smallvec", -======= name = "rust-argon2" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5565,20 +3407,13 @@ dependencies = [ "blake2b_simd", "constant_time_eq", "crossbeam-utils", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "rust-embed" -<<<<<<< HEAD -version = "5.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe1fe6aac5d6bb9e1ffd81002340363272a7648234ec7bdfac5ee202cb65523" -======= version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d40377bff8cceee81e28ddb73ac97f5c2856ce5522f0b260b763f434cdfae602" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -5587,15 +3422,9 @@ dependencies = [ [[package]] name = "rust-embed-impl" -<<<<<<< HEAD -version = "5.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed91c41c42ef7bf687384439c312e75e0da9c149b0390889b94de3c7d9d9e66" -======= version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "proc-macro2", "quote", @@ -5606,18 +3435,11 @@ dependencies = [ [[package]] name = "rust-embed-utils" -<<<<<<< HEAD -version = "5.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a512219132473ab0a77b52077059f1c47ce4af7fbdc94503e9862a34422876d" -dependencies = [ -======= version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad22c7226e4829104deab21df575e995bfbc4adfad13a595e387477f238c1aec" dependencies = [ - "sha2 0.9.9", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "sha2 0.9.8", "walkdir", ] @@ -5640,24 +3462,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] -<<<<<<< HEAD -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" - -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5667,80 +3471,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "rustversion" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" - -[[package]] -name = "rustyline" -version = "9.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790487c3881a63489ae77126f57048b42d62d3b2bafbf37453ea19eedb6340d6" -dependencies = [ - "bitflags", - "cfg-if 1.0.0", - "clipboard-win", - "dirs-next", - "fd-lock", - "libc", - "log", - "memchr", - "nix", - "radix_trie", - "scopeguard", - "smallvec", - "unicode-segmentation", - "unicode-width", - "utf8parse", - "winapi 0.3.9", -] - -[[package]] -name = "ryu" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" - -[[package]] -name = "s3handler" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b9590f1cae0b8b38aceabab05885c754416b6d33089c244a25441ae997fdb1" -dependencies = [ - "async-trait", - "base64", - "bytes 1.1.0", - "chrono", - "dyn-clone", - "failure", - "failure_derive", - "futures 0.3.18", - "hex", - "hmac", - "hmac-sha1", - "log", - "md5", - "mime_guess", - "quick-xml 0.22.0", - "regex", - "reqwest", - "rustc-serialize", - "serde", - "serde_derive", - "serde_json", - "sha2", - "tokio", - "url", -] - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" -======= name = "rustix" version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5756,16 +3486,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" [[package]] name = "same-file" @@ -5783,11 +3512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" dependencies = [ "lazy_static", -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -5814,15 +3539,9 @@ dependencies = [ [[package]] name = "security-framework" -<<<<<<< HEAD version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" -======= -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fed7948b6c68acbb6e20c334f55ad635dc0f75506963de4464289fbd3b051ac" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "bitflags", "core-foundation", @@ -5833,15 +3552,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -<<<<<<< HEAD version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" -======= -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57321bf8bc2362081b2599912d2961fe899c0efadf1b4b2f8d48b3e253bb96c" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "core-foundation-sys", "libc", @@ -5859,13 +3572,8 @@ dependencies = [ "fxhash", "log", "matches", -<<<<<<< HEAD - "phf", - "phf_codegen", -======= "phf 0.8.0", "phf_codegen 0.8.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "precomputed-hash", "servo_arc", "smallvec", @@ -5898,40 +3606,18 @@ dependencies = [ [[package]] name = "serde" -<<<<<<< HEAD version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" -======= -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "serde_derive", ] -[[package]] -<<<<<<< HEAD -name = "serde_bytes" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" -dependencies = [ - "serde", -] - [[package]] name = "serde_derive" version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" -======= -name = "serde_derive" -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "proc-macro2", "quote", @@ -5951,78 +3637,45 @@ dependencies = [ [[package]] name = "serde_json" -<<<<<<< HEAD version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" dependencies = [ "indexmap", "itoa", -======= -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" -dependencies = [ - "indexmap", - "itoa 1.0.1", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "ryu", "serde", ] [[package]] name = "serde_test" -<<<<<<< HEAD version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d82178225dbdeae2d5d190e8649287db6a3a32c6d24da22ae3146325aa353e4c" -======= -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21675ba6f9d97711cc00eee79d8dd7d0a31e571c350fb4d8a7c78f70c0e7b0e9" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "serde", ] [[package]] name = "serde_urlencoded" -<<<<<<< HEAD version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" dependencies = [ "form_urlencoded", "itoa", -======= -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa 1.0.1", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "ryu", "serde", ] [[package]] name = "serde_yaml" -<<<<<<< HEAD version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af" dependencies = [ "dtoa", "indexmap", -======= -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" -dependencies = [ - "indexmap", - "ryu", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "serde", "yaml-rust", ] @@ -6059,29 +3712,11 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -<<<<<<< HEAD -name = "sha1" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" - [[package]] name = "sha2" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" -dependencies = [ - "block-buffer", - "cfg-if 1.0.0", - "cpufeatures", - "digest", - "opaque-debug", -======= -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", @@ -6099,7 +3734,6 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.10.1", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -6114,28 +3748,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "shell-escape" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" - -[[package]] -name = "shell-words" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074" - -[[package]] -name = "signal-hook" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" -dependencies = [ - "libc", - "mio", - "signal-hook-registry", -======= name = "signal-hook" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6154,7 +3766,6 @@ dependencies = [ "libc", "mio", "signal-hook", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -6172,23 +3783,11 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c970da16e7c682fa90a261cf0724dee241c9f7831635ecc4e988ae8f3b505559" -[[package]] -<<<<<<< HEAD -name = "similar" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad1d488a557b235fc46dae55512ffbfc429d2482b08b4d9435ab07384ca8aec" - [[package]] name = "siphasher" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" -======= -name = "siphasher" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e" [[package]] name = "sized-chunks" @@ -6199,7 +3798,6 @@ dependencies = [ "bitmaps", "typenum", ] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "slab" @@ -6209,32 +3807,15 @@ checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "smallvec" -<<<<<<< HEAD version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" -[[package]] -name = "smart-default" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] -======= -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" - [[package]] name = "smawk" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "snap" @@ -6244,21 +3825,12 @@ checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451" [[package]] name = "socket2" -<<<<<<< HEAD version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" -dependencies = [ - "libc", - "winapi 0.3.9", -======= -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -6283,21 +3855,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -<<<<<<< HEAD -name = "std_prelude" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe" - -[[package]] -name = "str-buf" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "streaming-decompression" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6327,11 +3884,7 @@ dependencies = [ "lazy_static", "new_debug_unreachable", "parking_lot", -<<<<<<< HEAD - "phf_shared", -======= "phf_shared 0.8.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "precomputed-hash", "serde", ] @@ -6342,13 +3895,8 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" dependencies = [ -<<<<<<< HEAD - "phf_generator", - "phf_shared", -======= "phf_generator 0.8.0", "phf_shared 0.8.0", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "proc-macro2", "quote", ] @@ -6364,21 +3912,6 @@ dependencies = [ [[package]] name = "strum" -<<<<<<< HEAD -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" - -[[package]] -name = "strum_macros" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", -======= version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" @@ -6393,17 +3926,10 @@ dependencies = [ "proc-macro2", "quote", "rustversion", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "syn", ] [[package]] -<<<<<<< HEAD -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" -======= name = "supports-color" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6430,7 +3956,6 @@ checksum = "a8b945e45b417b125a8ec51f1b7df2f8df7920367700d1f98aedd21e5735f8b2" dependencies = [ "atty", ] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "sxd-document" @@ -6455,7 +3980,6 @@ dependencies = [ [[package]] name = "syn" -<<<<<<< HEAD version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" @@ -6466,61 +3990,6 @@ dependencies = [ ] [[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -======= -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" -dependencies = [ - "proc-macro2", - "quote", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce - "unicode-xid", -] - -[[package]] -<<<<<<< HEAD -name = "syntect" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b20815bbe80ee0be06e6957450a841185fcf690fe0178f14d77a05ce2caa031" -dependencies = [ - "bincode", - "bitflags", - "flate2", - "fnv", - "lazy_static", - "lazycell", - "onig", - "plist", - "regex-syntax", - "serde", - "serde_derive", - "serde_json", - "walkdir", - "yaml-rust", -] - -[[package]] -name = "sys-info" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c" -dependencies = [ - "cc", - "libc", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "sys-locale" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6530,65 +3999,36 @@ dependencies = [ "cstr_core", "libc", "web-sys", -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "sysinfo" -<<<<<<< HEAD -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e757000a4bed2b1be9be65a3f418b9696adf30bb419214c73997422de73a591" -dependencies = [ - "cfg-if 1.0.0", -======= version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f1bfab07306a27332451a662ca9c8156e3a9986f82660ba9c8e744fe8455d43" dependencies = [ "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "core-foundation-sys", "libc", "ntapi", "once_cell", "rayon", -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "tempfile" -<<<<<<< HEAD version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "rand 0.8.4", - "redox_syscall", - "remove_dir_all", - "winapi 0.3.9", -======= -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", "redox_syscall 0.2.10", "remove_dir_all", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -6604,25 +4044,6 @@ dependencies = [ [[package]] name = "term" -<<<<<<< HEAD -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi 0.3.9", -] - -[[package]] -name = "term_size" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" -dependencies = [ - "libc", - "winapi 0.3.9", -======= version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" @@ -6630,7 +4051,6 @@ dependencies = [ "byteorder", "dirs 1.0.5", "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -6649,9 +4069,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" dependencies = [ "libc", -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ] @@ -6670,7 +4087,6 @@ dependencies = [ "smawk", "unicode-linebreak", "unicode-width", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -6707,21 +4123,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", -<<<<<<< HEAD - "winapi 0.3.9", -] - -[[package]] -name = "time" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" -dependencies = [ - "itoa", - "libc", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -6751,53 +4153,18 @@ dependencies = [ [[package]] name = "tokio" -<<<<<<< HEAD version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" dependencies = [ "autocfg", - "bytes 1.1.0", -======= -version = "1.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" -dependencies = [ "bytes", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "libc", "memchr", "mio", "num_cpus", "pin-project-lite", -<<<<<<< HEAD - "tokio-macros", - "winapi 0.3.9", -] - -[[package]] -name = "tokio-io" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "log", -] - -[[package]] -name = "tokio-macros" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -6816,11 +4183,7 @@ version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ -<<<<<<< HEAD - "bytes 1.1.0", -======= "bytes", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "futures-core", "futures-sink", "log", @@ -6849,11 +4212,7 @@ version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ -<<<<<<< HEAD - "cfg-if 1.0.0", -======= "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "pin-project-lite", "tracing-core", ] @@ -6869,24 +4228,14 @@ dependencies = [ [[package]] name = "trash" -<<<<<<< HEAD version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3ebb6cb2db7947ab9f65dec9f7c5dbe01042b708f564242dcfb6d5cb2957cbc" -======= -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2ed4369f59214865022230fb397ad71353101fe87bfef0f0cf887c43eaa094" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "chrono", "libc", "log", "objc", -<<<<<<< HEAD -======= - "once_cell", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "scopeguard", "url", "windows", @@ -6899,22 +4248,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] -<<<<<<< HEAD -name = "tui" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "861d8f3ad314ede6219bcb2ab844054b1de279ee37a9bc38e3d606f9d3fb2a71" -dependencies = [ - "bitflags", - "cassowary", - "crossterm", - "unicode-segmentation", - "unicode-width", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "typed-arena" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6922,14 +4255,9 @@ checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d" [[package]] name = "typenum" -<<<<<<< HEAD version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" -======= -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "typetag" @@ -6954,7 +4282,6 @@ dependencies = [ "quote", "syn", ] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "ucd-trie" @@ -6964,31 +4291,17 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "umask" -<<<<<<< HEAD version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "982efbf70ec4d28f7862062c03dd1a4def601a5079e0faf1edc55f2ad0f6fe46" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -======= -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb3f38a494193b563eb215c43cb635a4fda1dfcd885fe3906b215bc6a9fb6b8" - [[package]] name = "uncased" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baeed7327e25054889b9bd4f975f32e5f4c5d434042d59ab6cd4142c0a76ed0" dependencies = [ - "version_check 0.9.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + "version_check 0.9.3", ] [[package]] @@ -6998,8 +4311,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] -<<<<<<< HEAD -======= name = "unicode-linebreak" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7009,7 +4320,6 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "unicode-normalization" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7055,19 +4365,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "user32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "users" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7101,11 +4398,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ -<<<<<<< HEAD "getrandom 0.2.3", -======= - "getrandom 0.2.4", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -7116,21 +4409,15 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -<<<<<<< HEAD -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" -======= version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "void" @@ -7160,8 +4447,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -======= name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7171,18 +4456,13 @@ dependencies = [ ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "walkdir" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "winapi-util", ] @@ -7210,33 +4490,19 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -<<<<<<< HEAD version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" -dependencies = [ - "cfg-if 1.0.0", -======= -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" dependencies = [ "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -<<<<<<< HEAD version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" -======= -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "bumpalo", "lazy_static", @@ -7249,19 +4515,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -<<<<<<< HEAD version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" -dependencies = [ - "cfg-if 1.0.0", -======= -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" dependencies = [ "cfg-if", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "js-sys", "wasm-bindgen", "web-sys", @@ -7269,15 +4527,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -<<<<<<< HEAD version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" -======= -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7285,15 +4537,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -<<<<<<< HEAD version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" -======= -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "proc-macro2", "quote", @@ -7304,7 +4550,6 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -<<<<<<< HEAD version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" @@ -7314,45 +4559,16 @@ name = "web-sys" version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" -======= -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" - -[[package]] -name = "web-sys" -version = "0.3.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -<<<<<<< HEAD -name = "webbrowser" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecad156490d6b620308ed411cfee90d280b3cbd13e189ea0d3fada8acc89158a" -dependencies = [ - "web-sys", - "widestring", - "winapi 0.3.9", -] - [[package]] name = "which" version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" -======= -name = "which" -version = "4.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "either", "lazy_static", @@ -7360,21 +4576,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "widestring" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7385,15 +4586,6 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[package]] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7405,11 +4597,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ -<<<<<<< HEAD - "winapi 0.3.9", -======= "winapi", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] @@ -7431,15 +4619,9 @@ dependencies = [ [[package]] name = "windows-sys" -<<<<<<< HEAD -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6" -======= version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "030b7ff91626e57a05ca64a07c481973cbb2db774e4852c9c7ca342408c6a99a" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -7450,15 +4632,9 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -<<<<<<< HEAD -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2" -======= version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "windows_gen" @@ -7471,17 +4647,6 @@ dependencies = [ [[package]] name = "windows_i686_gnu" -<<<<<<< HEAD -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a" - -[[package]] -name = "windows_i686_msvc" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64" -======= version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" @@ -7491,7 +4656,6 @@ name = "windows_i686_msvc" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "windows_macros" @@ -7505,17 +4669,6 @@ dependencies = [ [[package]] name = "windows_x86_64_gnu" -<<<<<<< HEAD -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f" -======= version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" @@ -7525,7 +4678,6 @@ name = "windows_x86_64_msvc" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [[package]] name = "winreg" @@ -7533,33 +4685,10 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ -<<<<<<< HEAD - "winapi 0.3.9", -] - -[[package]] -name = "x11" -version = "2.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd0565fa8bfba8c5efe02725b14dff114c866724eff2cfd44d76cea74bcd87a" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "xml-rs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" - -[[package]] -======= "winapi", ] [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "xmlparser" version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7575,15 +4704,12 @@ dependencies = [ ] [[package]] -<<<<<<< HEAD -======= name = "zeroize" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006" [[package]] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce name = "zip" version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7594,39 +4720,23 @@ dependencies = [ "crc32fast", "flate2", "thiserror", -<<<<<<< HEAD - "time 0.1.44", -======= "time", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ] [[package]] name = "zstd" -<<<<<<< HEAD version = "0.9.0+zstd.1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd" -======= -version = "0.9.2+zstd.1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -<<<<<<< HEAD version = "4.1.1+zstd.1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079" -======= -version = "4.1.3+zstd.1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "libc", "zstd-sys", @@ -7634,15 +4744,9 @@ dependencies = [ [[package]] name = "zstd-sys" -<<<<<<< HEAD version = "1.6.1+zstd.1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33" -======= -version = "1.6.2+zstd.1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 169e1a0c66..1b1c085ead 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,4 @@ [package] -<<<<<<< HEAD authors = ["The Nu Project Contributors"] default-run = "nu" description = "A new type of shell" @@ -11,149 +10,7 @@ license = "MIT" name = "nu" readme = "README.md" repository = "https://github.com/nushell/nushell" -version = "0.43.0" - -[workspace] -members = ["crates/*/"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -nu-cli = { version = "0.43.0", path="./crates/nu-cli", default-features=false } -nu-command = { version = "0.43.0", path="./crates/nu-command" } -nu-completion = { version = "0.43.0", path="./crates/nu-completion" } -nu-data = { version = "0.43.0", path="./crates/nu-data" } -nu-engine = { version = "0.43.0", path="./crates/nu-engine" } -nu-errors = { version = "0.43.0", path="./crates/nu-errors" } -nu-parser = { version = "0.43.0", path="./crates/nu-parser" } -nu-path = { version = "0.43.0", path="./crates/nu-path" } -nu-plugin = { version = "0.43.0", path="./crates/nu-plugin" } -nu-protocol = { version = "0.43.0", path="./crates/nu-protocol" } -nu-source = { version = "0.43.0", path="./crates/nu-source" } -nu-value-ext = { version = "0.43.0", path="./crates/nu-value-ext" } - -nu_plugin_binaryview = { version = "0.43.0", path="./crates/nu_plugin_binaryview", optional=true } -nu_plugin_chart = { version = "0.43.0", path="./crates/nu_plugin_chart", optional=true } -nu_plugin_from_bson = { version = "0.43.0", path="./crates/nu_plugin_from_bson", optional=true } -nu_plugin_from_sqlite = { version = "0.43.0", path="./crates/nu_plugin_from_sqlite", optional=true } -nu_plugin_inc = { version = "0.43.0", path="./crates/nu_plugin_inc", optional=true } -nu_plugin_match = { version = "0.43.0", path="./crates/nu_plugin_match", optional=true } -nu_plugin_query_json = { version = "0.43.0", path="./crates/nu_plugin_query_json", optional=true } -nu_plugin_s3 = { version = "0.43.0", path="./crates/nu_plugin_s3", optional=true } -nu_plugin_selector = { version = "0.43.0", path="./crates/nu_plugin_selector", optional=true } -nu_plugin_start = { version = "0.43.0", path="./crates/nu_plugin_start", optional=true } -nu_plugin_textview = { version = "0.43.0", path="./crates/nu_plugin_textview", optional=true } -nu_plugin_to_bson = { version = "0.43.0", path="./crates/nu_plugin_to_bson", optional=true } -nu_plugin_to_sqlite = { version = "0.43.0", path="./crates/nu_plugin_to_sqlite", optional=true } -nu_plugin_tree = { version = "0.43.0", path="./crates/nu_plugin_tree", optional=true } -nu_plugin_xpath = { version = "0.43.0", path="./crates/nu_plugin_xpath", optional=true } - -# Required to bootstrap the main binary -ctrlc = { version="3.1.7", optional=true } -futures = { version="0.3.12", features=["compat", "io-compat"] } -itertools = "0.10.0" - -[dev-dependencies] -nu-test-support = { version = "0.43.0", path="./crates/nu-test-support" } -serial_test = "0.5.1" -hamcrest2 = "0.3.0" -rstest = "0.10.0" - -[build-dependencies] - -[features] -fetch-support = ["nu-command/fetch", "nu-command/post"] -sys-support = ["nu-command/sys", "nu-command/ps"] -ctrlc-support = ["nu-cli/ctrlc", "nu-command/ctrlc"] -rustyline-support = ["nu-cli/rustyline-support", "nu-command/rustyline-support"] -term-support = ["nu-command/term"] -uuid-support = ["nu-command/uuid_crate"] -which-support = ["nu-command/which", "nu-engine/which"] - -default = [ - "nu-cli/shadow-rs", - "sys-support", - "ctrlc-support", - "which-support", - "term-support", - "rustyline-support", - "match", - "fetch-support", - "zip-support", - "dataframe", -] - -stable = ["default"] -extra = [ - "default", - "binaryview", - "inc", - "tree", - "textview", - "trash-support", - "uuid-support", - "start", - "bson", - "sqlite", - "s3", - "chart", - "xpath", - "selector", - "query-json", -] - -wasi = ["inc", "match", "match", "tree", "rustyline-support"] - -# Stable (Default) -inc = ["nu_plugin_inc"] -match = ["nu_plugin_match"] -textview = ["nu_plugin_textview"] - -# Extra -binaryview = ["nu_plugin_binaryview"] -bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"] -chart = ["nu_plugin_chart"] -query-json = ["nu_plugin_query_json"] -s3 = ["nu_plugin_s3"] -selector = ["nu_plugin_selector"] -sqlite = ["nu_plugin_from_sqlite", "nu_plugin_to_sqlite"] -start = ["nu_plugin_start"] -trash-support = [ - "nu-command/trash-support", - "nu-engine/trash-support", -] -tree = ["nu_plugin_tree"] -xpath = ["nu_plugin_xpath"] -zip-support = ["nu-command/zip"] - -#dataframe feature for nushell -dataframe = [ - "nu-engine/dataframe", - "nu-protocol/dataframe", - "nu-command/dataframe", - "nu-value-ext/dataframe", - "nu-data/dataframe", - "nu_plugin_to_bson/dataframe", -] - -[profile.release] -opt-level = "s" # Optimize for size. - -# Core plugins that ship with `cargo install nu` by default -# Currently, Cargo limits us to installing only one binary -# unless we use [[bin]], so we use this as a workaround -[[bin]] -name = "nu_plugin_core_textview" -path = "src/plugins/nu_plugin_core_textview.rs" -required-features = ["textview"] - -[[bin]] -name = "nu_plugin_core_inc" -======= -name = "nu" -version = "0.1.0" -edition = "2021" -default-run = "nu" +version = "0.59.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -176,21 +33,23 @@ members = [ reedline = { git = "https://github.com/nushell/reedline", branch = "main" } crossterm = "0.22.*" -nu-cli = { path="./crates/nu-cli" } -nu-command = { path="./crates/nu-command" } -nu-engine = { path="./crates/nu-engine" } -nu-json = { path="./crates/nu-json" } -nu-parser = { path="./crates/nu-parser" } -nu-path = { path="./crates/nu-path" } -nu-pretty-hex = { path = "./crates/nu-pretty-hex" } -nu-protocol = { path = "./crates/nu-protocol" } -nu-plugin = { path = "./crates/nu-plugin", optional = true } -nu-system = { path = "./crates/nu-system"} -nu-table = { path = "./crates/nu-table" } -nu-term-grid = { path = "./crates/nu-term-grid" } - +nu-cli = { path="./crates/nu-cli", version = "0.59.0" } +nu-command = { path="./crates/nu-command", version = "0.59.0" } +nu-engine = { path="./crates/nu-engine", version = "0.59.0" } +nu-json = { path="./crates/nu-json", version = "0.59.0" } +nu-parser = { path="./crates/nu-parser", version = "0.59.0" } +nu-path = { path="./crates/nu-path", version = "0.59.0" } +nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.59.0" } +nu-protocol = { path = "./crates/nu-protocol", version = "0.59.0" } +nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.59.0" } +nu-system = { path = "./crates/nu-system", version = "0.59.0" } +nu-table = { path = "./crates/nu-table", version = "0.59.0" } +nu-term-grid = { path = "./crates/nu-term-grid", version = "0.59.0" } +# nu-ansi-term = { path = "./crates/nu-ansi-term", version = "0.59.0" } nu-ansi-term = "0.42.0" -nu-color-config = { path = "./crates/nu-color-config" } + +nu-color-config = { path = "./crates/nu-color-config", version = "0.59.0" } + miette = "3.0.0" ctrlc = "3.2.1" crossterm_winapi = "0.9.0" @@ -199,10 +58,10 @@ pretty_env_logger = "0.4.0" # mimalloc = { version = "*", default-features = false } -nu_plugin_inc = { version = "0.1.0", path = "./crates/nu_plugin_inc", optional = true } -nu_plugin_example = { version = "0.1.0", path = "./crates/nu_plugin_example", optional = true } -nu_plugin_gstat = { version = "0.1.0", path = "./crates/nu_plugin_gstat", optional = true } -nu_plugin_query = { version = "0.1.0", path = "./crates/nu_plugin_query", optional = true } +nu_plugin_inc = { version = "0.59.0", path = "./crates/nu_plugin_inc", optional = true } +nu_plugin_example = { version = "0.59.0", path = "./crates/nu_plugin_example", optional = true } +nu_plugin_gstat = { version = "0.59.0", path = "./crates/nu_plugin_gstat", optional = true } +nu_plugin_query = { version = "0.59.0", path = "./crates/nu_plugin_query", optional = true } [dev-dependencies] nu-test-support = { path="./crates/nu-test-support" } @@ -254,83 +113,10 @@ opt-level = "s" # Optimize for size # Build plugins [[bin]] name = "nu_plugin_inc" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce path = "src/plugins/nu_plugin_core_inc.rs" required-features = ["inc"] [[bin]] -<<<<<<< HEAD -name = "nu_plugin_core_match" -path = "src/plugins/nu_plugin_core_match.rs" -required-features = ["match"] - -# Extra plugins - -[[bin]] -name = "nu_plugin_extra_binaryview" -path = "src/plugins/nu_plugin_extra_binaryview.rs" -required-features = ["binaryview"] - -[[bin]] -name = "nu_plugin_extra_tree" -path = "src/plugins/nu_plugin_extra_tree.rs" -required-features = ["tree"] - -[[bin]] -name = "nu_plugin_extra_query_json" -path = "src/plugins/nu_plugin_extra_query_json.rs" -required-features = ["query-json"] - -[[bin]] -name = "nu_plugin_extra_start" -path = "src/plugins/nu_plugin_extra_start.rs" -required-features = ["start"] - -[[bin]] -name = "nu_plugin_extra_s3" -path = "src/plugins/nu_plugin_extra_s3.rs" -required-features = ["s3"] - -[[bin]] -name = "nu_plugin_extra_chart_bar" -path = "src/plugins/nu_plugin_extra_chart_bar.rs" -required-features = ["chart"] - -[[bin]] -name = "nu_plugin_extra_chart_line" -path = "src/plugins/nu_plugin_extra_chart_line.rs" -required-features = ["chart"] - -[[bin]] -name = "nu_plugin_extra_xpath" -path = "src/plugins/nu_plugin_extra_xpath.rs" -required-features = ["xpath"] - -[[bin]] -name = "nu_plugin_extra_selector" -path = "src/plugins/nu_plugin_extra_selector.rs" -required-features = ["selector"] - -[[bin]] -name = "nu_plugin_extra_from_bson" -path = "src/plugins/nu_plugin_extra_from_bson.rs" -required-features = ["bson"] - -[[bin]] -name = "nu_plugin_extra_to_bson" -path = "src/plugins/nu_plugin_extra_to_bson.rs" -required-features = ["bson"] - -[[bin]] -name = "nu_plugin_extra_from_sqlite" -path = "src/plugins/nu_plugin_extra_from_sqlite.rs" -required-features = ["sqlite"] - -[[bin]] -name = "nu_plugin_extra_to_sqlite" -path = "src/plugins/nu_plugin_extra_to_sqlite.rs" -required-features = ["sqlite"] -======= name = "nu_plugin_example" path = "src/plugins/nu_plugin_core_example.rs" required-features = ["example"] @@ -345,7 +131,6 @@ required-features = ["gstat"] name = "nu_plugin_query" path = "src/plugins/nu_plugin_extra_query.rs" required-features = ["query"] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce # Main nu binary [[bin]] diff --git a/Cargo.toml.old b/Cargo.toml.old new file mode 100644 index 0000000000..e20ef867eb --- /dev/null +++ b/Cargo.toml.old @@ -0,0 +1,229 @@ +[package] +authors = ["The Nu Project Contributors"] +default-run = "nu" +description = "A new type of shell" +documentation = "https://www.nushell.sh/book/" +edition = "2018" +exclude = ["images"] +homepage = "https://www.nushell.sh" +license = "MIT" +name = "nu" +readme = "README.md" +repository = "https://github.com/nushell/nushell" +version = "0.59.0" + +[workspace] +members = ["crates/*/"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nu-cli = { version = "0.59.0", path="./crates/nu-cli", default-features=false } +nu-command = { version = "0.59.0", path="./crates/nu-command" } +nu-completion = { version = "0.59.0", path="./crates/nu-completion" } +nu-data = { version = "0.59.0", path="./crates/nu-data" } +nu-engine = { version = "0.59.0", path="./crates/nu-engine" } +nu-errors = { version = "0.59.0", path="./crates/nu-errors" } +nu-parser = { version = "0.59.0", path="./crates/nu-parser" } +nu-path = { version = "0.59.0", path="./crates/nu-path" } +nu-plugin = { version = "0.59.0", path="./crates/nu-plugin" } +nu-protocol = { version = "0.59.0", path="./crates/nu-protocol" } +nu-source = { version = "0.59.0", path="./crates/nu-source" } +nu-value-ext = { version = "0.59.0", path="./crates/nu-value-ext" } + +# nu_plugin_binaryview = { version = "0.59.0", path="./crates/nu_plugin_binaryview", optional=true } +# nu_plugin_chart = { version = "0.59.0", path="./crates/nu_plugin_chart", optional=true } +# nu_plugin_from_bson = { version = "0.59.0", path="./crates/nu_plugin_from_bson", optional=true } +# nu_plugin_from_sqlite = { version = "0.59.0", path="./crates/nu_plugin_from_sqlite", optional=true } +# nu_plugin_inc = { version = "0.59.0", path="./crates/nu_plugin_inc", optional=true } +# nu_plugin_match = { version = "0.59.0", path="./crates/nu_plugin_match", optional=true } +# nu_plugin_query_json = { version = "0.59.0", path="./crates/nu_plugin_query_json", optional=true } +# nu_plugin_s3 = { version = "0.59.0", path="./crates/nu_plugin_s3", optional=true } +# nu_plugin_selector = { version = "0.59.0", path="./crates/nu_plugin_selector", optional=true } +# nu_plugin_start = { version = "0.59.0", path="./crates/nu_plugin_start", optional=true } +# nu_plugin_textview = { version = "0.59.0", path="./crates/nu_plugin_textview", optional=true } +# nu_plugin_to_bson = { version = "0.59.0", path="./crates/nu_plugin_to_bson", optional=true } +# nu_plugin_to_sqlite = { version = "0.59.0", path="./crates/nu_plugin_to_sqlite", optional=true } +# nu_plugin_tree = { version = "0.59.0", path="./crates/nu_plugin_tree", optional=true } +# nu_plugin_xpath = { version = "0.59.0", path="./crates/nu_plugin_xpath", optional=true } + +# Required to bootstrap the main binary +ctrlc = { version="3.1.7", optional=true } +futures = { version="0.3.12", features=["compat", "io-compat"] } +itertools = "0.10.0" + +[dev-dependencies] +nu-test-support = { version = "0.59.0", path="./crates/nu-test-support" } +serial_test = "0.5.1" +hamcrest2 = "0.3.0" +rstest = "0.10.0" + +[build-dependencies] + +[features] +fetch-support = ["nu-command/fetch", "nu-command/post"] +sys-support = ["nu-command/sys", "nu-command/ps"] +ctrlc-support = ["nu-cli/ctrlc", "nu-command/ctrlc"] +rustyline-support = ["nu-cli/rustyline-support", "nu-command/rustyline-support"] +term-support = ["nu-command/term"] +uuid-support = ["nu-command/uuid_crate"] +which-support = ["nu-command/which", "nu-engine/which"] + +default = [ + "nu-cli/shadow-rs", + "sys-support", + "ctrlc-support", + "which-support", + "term-support", + "rustyline-support", + # "match", + "fetch-support", + "zip-support", + "dataframe", +] + +stable = ["default"] +extra = [ + "default", + # "binaryview", + # "inc", + # "tree", + # "textview", + "trash-support", + "uuid-support", + # "start", + # "bson", + # "sqlite", + # "s3", + # "chart", + # "xpath", + # "selector", + # "query-json", +] + +# wasi = ["inc", "match", "match", "tree", "rustyline-support"] + +# Stable (Default) +# inc = ["nu_plugin_inc"] +# match = ["nu_plugin_match"] +# textview = ["nu_plugin_textview"] + +# Extra +# binaryview = ["nu_plugin_binaryview"] +# bson = ["nu_plugin_from_bson", "nu_plugin_to_bson"] +# chart = ["nu_plugin_chart"] +# query-json = ["nu_plugin_query_json"] +# s3 = ["nu_plugin_s3"] +# selector = ["nu_plugin_selector"] +# sqlite = ["nu_plugin_from_sqlite", "nu_plugin_to_sqlite"] +# start = ["nu_plugin_start"] +trash-support = [ + "nu-command/trash-support", + "nu-engine/trash-support", +] +# tree = ["nu_plugin_tree"] +# xpath = ["nu_plugin_xpath"] +zip-support = ["nu-command/zip"] + +#dataframe feature for nushell +dataframe = [ + "nu-engine/dataframe", + "nu-protocol/dataframe", + "nu-command/dataframe", + "nu-value-ext/dataframe", + "nu-data/dataframe", + # "nu_plugin_to_bson/dataframe", +] + +[profile.release] +opt-level = "s" # Optimize for size. + +# Core plugins that ship with `cargo install nu` by default +# Currently, Cargo limits us to installing only one binary +# unless we use [[bin]], so we use this as a workaround +# [[bin]] +# name = "nu_plugin_core_textview" +# path = "src/plugins/nu_plugin_core_textview.rs" +# required-features = ["textview"] +# +# [[bin]] +# name = "nu_plugin_core_inc" +# path = "src/plugins/nu_plugin_core_inc.rs" +# required-features = ["inc"] +# +# [[bin]] +# name = "nu_plugin_core_match" +# path = "src/plugins/nu_plugin_core_match.rs" +# required-features = ["match"] +# +# # Extra plugins +# +# [[bin]] +# name = "nu_plugin_extra_binaryview" +# path = "src/plugins/nu_plugin_extra_binaryview.rs" +# required-features = ["binaryview"] +# +# [[bin]] +# name = "nu_plugin_extra_tree" +# path = "src/plugins/nu_plugin_extra_tree.rs" +# required-features = ["tree"] +# +# [[bin]] +# name = "nu_plugin_extra_query_json" +# path = "src/plugins/nu_plugin_extra_query_json.rs" +# required-features = ["query-json"] +# +# [[bin]] +# name = "nu_plugin_extra_start" +# path = "src/plugins/nu_plugin_extra_start.rs" +# required-features = ["start"] +# +# [[bin]] +# name = "nu_plugin_extra_s3" +# path = "src/plugins/nu_plugin_extra_s3.rs" +# required-features = ["s3"] +# +# [[bin]] +# name = "nu_plugin_extra_chart_bar" +# path = "src/plugins/nu_plugin_extra_chart_bar.rs" +# required-features = ["chart"] +# +# [[bin]] +# name = "nu_plugin_extra_chart_line" +# path = "src/plugins/nu_plugin_extra_chart_line.rs" +# required-features = ["chart"] +# +# [[bin]] +# name = "nu_plugin_extra_xpath" +# path = "src/plugins/nu_plugin_extra_xpath.rs" +# required-features = ["xpath"] +# +# [[bin]] +# name = "nu_plugin_extra_selector" +# path = "src/plugins/nu_plugin_extra_selector.rs" +# required-features = ["selector"] +# +# [[bin]] +# name = "nu_plugin_extra_from_bson" +# path = "src/plugins/nu_plugin_extra_from_bson.rs" +# required-features = ["bson"] +# +# [[bin]] +# name = "nu_plugin_extra_to_bson" +# path = "src/plugins/nu_plugin_extra_to_bson.rs" +# required-features = ["bson"] +# +# [[bin]] +# name = "nu_plugin_extra_from_sqlite" +# path = "src/plugins/nu_plugin_extra_from_sqlite.rs" +# required-features = ["sqlite"] +# +# [[bin]] +# name = "nu_plugin_extra_to_sqlite" +# path = "src/plugins/nu_plugin_extra_to_sqlite.rs" +# required-features = ["sqlite"] +# +# Main nu binary +[[bin]] +name = "nu" +path = "src/main.rs" diff --git a/README.md b/README.md index d77e61f103..ea2da1fb1d 100644 --- a/README.md +++ b/README.md @@ -281,7 +281,3 @@ Thanks to all the people who already contributed! ## License The project is made available under the MIT license. See the `LICENSE` file for more information. -======= -# NOTE: Engine-q is merged into Nushell - -Please use https://github.com/nushell/nushell diff --git a/crates/README.md b/crates/README.md new file mode 100644 index 0000000000..ca1e44bcc2 --- /dev/null +++ b/crates/README.md @@ -0,0 +1,13 @@ +# Nushell core libraries and plugins + +These sub-crates form both the foundation for Nu and a set of plugins which extend Nu with additional functionality. + +Foundational libraries are split into two kinds of crates: + +* Core crates - those crates that work together to build the Nushell language engine +* Support crates - a set of crates that support the engine with additional features like JSON support, ANSI support, and more. + +Plugins are likewise also split into two types: + +* Core plugins - plugins that provide part of the default experience of Nu, including access to the system properties, processes, and web-connectivity features. +* Extra plugins - these plugins run a wide range of different capabilities like working with different file types, charting, viewing binary data, and more. diff --git a/crates/nu-ansi-term/.gitignore b/crates/nu-ansi-term/.gitignore new file mode 100644 index 0000000000..f2f9e58ec3 --- /dev/null +++ b/crates/nu-ansi-term/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock \ No newline at end of file diff --git a/crates/nu-ansi-term/Cargo.toml b/crates/nu-ansi-term/Cargo.toml new file mode 100644 index 0000000000..48ac4dc3c5 --- /dev/null +++ b/crates/nu-ansi-term/Cargo.toml @@ -0,0 +1,39 @@ +[package] +authors = [ + "ogham@bsago.me", + "Ryan Scheel (Havvy) ", + "Josh Triplett ", + "The Nu Project Contributors", +] +description = "Library for ANSI terminal colors and styles (bold, underline)" +edition = "2018" +license = "MIT" +name = "nu-ansi-term" +version = "0.42.0" + +[lib] +doctest = false +# name = "nu-ansi-term" + +[features] +derive_serde_style = ["serde"] + +[dependencies] +overload = "0.1.1" +serde = { version="1.0.90", features=["derive"], optional=true } + +# [dependencies.serde] +# version = "1.0.90" +# features = ["derive"] +# optional = true + +[target.'cfg(target_os="windows")'.dependencies.winapi] +version = "0.3.4" +features = ["consoleapi", "errhandlingapi", "fileapi", "handleapi", "processenv"] + +[dev-dependencies] +doc-comment = "0.3" +regex = "1.1.9" + +[dev-dependencies.serde_json] +version = "1.0.39" diff --git a/crates/nu-ansi-term/LICENCE b/crates/nu-ansi-term/LICENCE new file mode 100644 index 0000000000..3228cc99b2 --- /dev/null +++ b/crates/nu-ansi-term/LICENCE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Benjamin Sago + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/nu-ansi-term/README.md b/crates/nu-ansi-term/README.md new file mode 100644 index 0000000000..8143bb4d3d --- /dev/null +++ b/crates/nu-ansi-term/README.md @@ -0,0 +1,182 @@ +# nu-ansi-term + +> This is a copy of rust-ansi-term but with Color change to Color and light foreground colors added (90-97) as well as light background colors added (100-107). + +This is a library for controlling colors and formatting, such as red bold text or blue underlined text, on ANSI terminals. + +### [View the Rustdoc](https://docs.rs/nu_ansi_term/) + +# Installation + +This crate works with [Cargo](http://crates.io). Add the following to your `Cargo.toml` dependencies section: + +```toml +[dependencies] +nu_ansi_term = "0.13" +``` + +## Basic usage + +There are three main types in this crate that you need to be concerned with: `ANSIString`, `Style`, and `Color`. + +A `Style` holds stylistic information: foreground and background colors, whether the text should be bold, or blinking, or other properties. +The `Color` enum represents the available colors. +And an `ANSIString` is a string paired with a `Style`. + +`Color` is also available as an alias to `Color`. + +To format a string, call the `paint` method on a `Style` or a `Color`, passing in the string you want to format as the argument. +For example, here’s how to get some red text: + +```rust +use nu_ansi_term::Color::Red; + +println!("This is in red: {}", Red.paint("a red string")); +``` + +It’s important to note that the `paint` method does _not_ actually return a string with the ANSI control characters surrounding it. +Instead, it returns an `ANSIString` value that has a `Display` implementation that, when formatted, returns the characters. +This allows strings to be printed with a minimum of `String` allocations being performed behind the scenes. + +If you _do_ want to get at the escape codes, then you can convert the `ANSIString` to a string as you would any other `Display` value: + +```rust +use nu_ansi_term::Color::Red; + +let red_string = Red.paint("a red string").to_string(); +``` + +**Note for Windows 10 users:** On Windows 10, the application must enable ANSI support first: + +```rust,ignore +let enabled = nu_ansi_term::enable_ansi_support(); +``` + +## Bold, underline, background, and other styles + +For anything more complex than plain foreground color changes, you need to construct `Style` values themselves, rather than beginning with a `Color`. +You can do this by chaining methods based on a new `Style`, created with `Style::new()`. +Each method creates a new style that has that specific property set. +For example: + +```rust +use nu_ansi_term::Style; + +println!("How about some {} and {}?", + Style::new().bold().paint("bold"), + Style::new().underline().paint("underline")); +``` + +For brevity, these methods have also been implemented for `Color` values, so you can give your styles a foreground color without having to begin with an empty `Style` value: + +```rust +use nu_ansi_term::Color::{Blue, Yellow}; + +println!("Demonstrating {} and {}!", + Blue.bold().paint("blue bold"), + Yellow.underline().paint("yellow underline")); + +println!("Yellow on blue: {}", Yellow.on(Blue).paint("wow!")); +``` + +The complete list of styles you can use are: +`bold`, `dimmed`, `italic`, `underline`, `blink`, `reverse`, `hidden`, and `on` for background colors. + +In some cases, you may find it easier to change the foreground on an existing `Style` rather than starting from the appropriate `Color`. +You can do this using the `fg` method: + +```rust +use nu_ansi_term::Style; +use nu_ansi_term::Color::{Blue, Cyan, Yellow}; + +println!("Yellow on blue: {}", Style::new().on(Blue).fg(Yellow).paint("yow!")); +println!("Also yellow on blue: {}", Cyan.on(Blue).fg(Yellow).paint("zow!")); +``` + +You can turn a `Color` into a `Style` with the `normal` method. +This will produce the exact same `ANSIString` as if you just used the `paint` method on the `Color` directly, but it’s useful in certain cases: for example, you may have a method that returns `Styles`, and need to represent both the β€œred bold” and β€œred, but not bold” styles with values of the same type. The `Style` struct also has a `Default` implementation if you want to have a style with _nothing_ set. + +```rust +use nu_ansi_term::Style; +use nu_ansi_term::Color::Red; + +Red.normal().paint("yet another red string"); +Style::default().paint("a completely regular string"); +``` + +## Extended colors + +You can access the extended range of 256 colors by using the `Color::Fixed` variant, which takes an argument of the color number to use. +This can be included wherever you would use a `Color`: + +```rust +use nu_ansi_term::Color::Fixed; + +Fixed(134).paint("A sort of light purple"); +Fixed(221).on(Fixed(124)).paint("Mustard in the ketchup"); +``` + +The first sixteen of these values are the same as the normal and bold standard color variants. +There’s nothing stopping you from using these as `Fixed` colors instead, but there’s nothing to be gained by doing so either. + +You can also access full 24-bit color by using the `Color::RGB` variant, which takes separate `u8` arguments for red, green, and blue: + +```rust +use nu_ansi_term::Color::RGB; + +RGB(70, 130, 180).paint("Steel blue"); +``` + +## Combining successive coloured strings + +The benefit of writing ANSI escape codes to the terminal is that they _stack_: you do not need to end every coloured string with a reset code if the text that follows it is of a similar style. +For example, if you want to have some blue text followed by some blue bold text, it’s possible to send the ANSI code for blue, followed by the ANSI code for bold, and finishing with a reset code without having to have an extra one between the two strings. + +This crate can optimise the ANSI codes that get printed in situations like this, making life easier for your terminal renderer. +The `ANSIStrings` struct takes a slice of several `ANSIString` values, and will iterate over each of them, printing only the codes for the styles that need to be updated as part of its formatting routine. + +The following code snippet uses this to enclose a binary number displayed in red bold text inside some red, but not bold, brackets: + +```rust +use nu_ansi_term::Color::Red; +use nu_ansi_term::{ANSIString, ANSIStrings}; + +let some_value = format!("{:b}", 42); +let strings: &[ANSIString<'static>] = &[ + Red.paint("["), + Red.bold().paint(some_value), + Red.paint("]"), +]; + +println!("Value: {}", ANSIStrings(strings)); +``` + +There are several things to note here. +Firstly, the `paint` method can take _either_ an owned `String` or a borrowed `&str`. +Internally, an `ANSIString` holds a copy-on-write (`Cow`) string value to deal with both owned and borrowed strings at the same time. +This is used here to display a `String`, the result of the `format!` call, using the same mechanism as some statically-available `&str` slices. +Secondly, that the `ANSIStrings` value works in the same way as its singular counterpart, with a `Display` implementation that only performs the formatting when required. + +## Byte strings + +This library also supports formatting `[u8]` byte strings; this supports applications working with text in an unknown encoding. +`Style` and `Color` support painting `[u8]` values, resulting in an `ANSIByteString`. +This type does not implement `Display`, as it may not contain UTF-8, but it does provide a method `write_to` to write the result to any value that implements `Write`: + +```rust +use nu_ansi_term::Color::Green; + +Green.paint("user data".as_bytes()).write_to(&mut std::io::stdout()).unwrap(); +``` + +Similarly, the type `ANSIByteStrings` supports writing a list of `ANSIByteString` values with minimal escape sequences: + +```rust +use nu_ansi_term::Color::Green; +use nu_ansi_term::ANSIByteStrings; + +ANSIByteStrings(&[ + Green.paint("user data 1\n".as_bytes()), + Green.bold().paint("user data 2\n".as_bytes()), +]).write_to(&mut std::io::stdout()).unwrap(); +``` diff --git a/crates/nu-ansi-term/examples/256_colors.rs b/crates/nu-ansi-term/examples/256_colors.rs new file mode 100644 index 0000000000..4766dcdb63 --- /dev/null +++ b/crates/nu-ansi-term/examples/256_colors.rs @@ -0,0 +1,72 @@ +extern crate nu_ansi_term; +use nu_ansi_term::Color; + +// This example prints out the 256 colors. +// They're arranged like this: +// +// - 0 to 8 are the eight standard colors. +// - 9 to 15 are the eight bold colors. +// - 16 to 231 are six blocks of six-by-six color squares. +// - 232 to 255 are shades of grey. + +fn main() { + // First two lines + for c in 0..8 { + glow(c, c != 0); + print!(" "); + } + println!(); + for c in 8..16 { + glow(c, c != 8); + print!(" "); + } + println!("\n"); + + // Six lines of the first three squares + for row in 0..6 { + for square in 0..3 { + for column in 0..6 { + glow(16 + square * 36 + row * 6 + column, row >= 3); + print!(" "); + } + + print!(" "); + } + + println!(); + } + println!(); + + // Six more lines of the other three squares + for row in 0..6 { + for square in 0..3 { + for column in 0..6 { + glow(124 + square * 36 + row * 6 + column, row >= 3); + print!(" "); + } + + print!(" "); + } + + println!(); + } + println!(); + + // The last greyscale lines + for c in 232..=243 { + glow(c, false); + print!(" "); + } + println!(); + for c in 244..=255 { + glow(c, true); + print!(" "); + } + println!(); +} + +fn glow(c: u8, light_bg: bool) { + let base = if light_bg { Color::Black } else { Color::White }; + let style = base.on(Color::Fixed(c)); + print!("{}", style.paint(&format!(" {:3} ", c))); +} diff --git a/crates/nu-ansi-term/examples/basic_colors.rs b/crates/nu-ansi-term/examples/basic_colors.rs new file mode 100644 index 0000000000..3c2b6817fe --- /dev/null +++ b/crates/nu-ansi-term/examples/basic_colors.rs @@ -0,0 +1,18 @@ +extern crate nu_ansi_term; +use nu_ansi_term::{Color::*, Style}; + +// This example prints out the 16 basic colors. + +fn main() { + let normal = Style::default(); + + println!("{} {}", normal.paint("Normal"), normal.bold().paint("bold")); + println!("{} {}", Black.paint("Black"), Black.bold().paint("bold")); + println!("{} {}", Red.paint("Red"), Red.bold().paint("bold")); + println!("{} {}", Green.paint("Green"), Green.bold().paint("bold")); + println!("{} {}", Yellow.paint("Yellow"), Yellow.bold().paint("bold")); + println!("{} {}", Blue.paint("Blue"), Blue.bold().paint("bold")); + println!("{} {}", Purple.paint("Purple"), Purple.bold().paint("bold")); + println!("{} {}", Cyan.paint("Cyan"), Cyan.bold().paint("bold")); + println!("{} {}", White.paint("White"), White.bold().paint("bold")); +} diff --git a/crates/nu-ansi-term/examples/gradient_colors.rs b/crates/nu-ansi-term/examples/gradient_colors.rs new file mode 100644 index 0000000000..1c95838654 --- /dev/null +++ b/crates/nu-ansi-term/examples/gradient_colors.rs @@ -0,0 +1,37 @@ +use nu_ansi_term::{build_all_gradient_text, Color, Gradient, Rgb, TargetGround}; + +fn main() { + let text = "lorem ipsum quia dolor sit amet, consectetur, adipisci velit"; + + // a gradient from hex colors + let start = Rgb::from_hex(0x40c9ff); + let end = Rgb::from_hex(0xe81cff); + let grad0 = Gradient::new(start, end); + + // a gradient from color::rgb() + let start = Color::Rgb(64, 201, 255); + let end = Color::Rgb(232, 28, 255); + let gradient = Gradient::from_color_rgb(start, end); + + // a slightly different gradient + let start2 = Color::Rgb(128, 64, 255); + let end2 = Color::Rgb(0, 28, 255); + let gradient2 = Gradient::from_color_rgb(start2, end2); + + // reverse the gradient + let gradient3 = gradient.reverse(); + + let build_fg = gradient.build(text, TargetGround::Foreground); + println!("{}", build_fg); + let build_bg = gradient.build(text, TargetGround::Background); + println!("{}", build_bg); + let bgt = build_all_gradient_text(text, gradient, gradient2); + println!("{}", bgt); + let bgt2 = build_all_gradient_text(text, gradient, gradient3); + println!("{}", bgt2); + + println!( + "{}", + grad0.build("nushell is awesome", TargetGround::Foreground) + ); +} diff --git a/crates/nu-ansi-term/examples/rgb_colors.rs b/crates/nu-ansi-term/examples/rgb_colors.rs new file mode 100644 index 0000000000..4657d401f4 --- /dev/null +++ b/crates/nu-ansi-term/examples/rgb_colors.rs @@ -0,0 +1,23 @@ +extern crate nu_ansi_term; +use nu_ansi_term::{Color, Style}; + +// This example prints out a color gradient in a grid by calculating each +// character’s red, green, and blue components, and using 24-bit color codes +// to display them. + +const WIDTH: i32 = 80; +const HEIGHT: i32 = 24; + +fn main() { + for row in 0..HEIGHT { + for col in 0..WIDTH { + let r = (row * 255 / HEIGHT) as u8; + let g = (col * 255 / WIDTH) as u8; + let b = 128; + + print!("{}", Style::default().on(Color::Rgb(r, g, b)).paint(" ")); + } + + println!(); + } +} diff --git a/crates/nu-ansi-term/src/ansi.rs b/crates/nu-ansi-term/src/ansi.rs new file mode 100644 index 0000000000..8f2454dba6 --- /dev/null +++ b/crates/nu-ansi-term/src/ansi.rs @@ -0,0 +1,405 @@ +#![allow(missing_docs)] +use crate::style::{Color, Style}; +use crate::write::AnyWrite; +use std::fmt; + +impl Style { + /// Write any bytes that go *before* a piece of text to the given writer. + fn write_prefix(&self, f: &mut W) -> Result<(), W::Error> { + // If there are actually no styles here, then don’t write *any* codes + // as the prefix. An empty ANSI code may not affect the terminal + // output at all, but a user may just want a code-free string. + if self.is_plain() { + return Ok(()); + } + + // Write the codes’ prefix, then write numbers, separated by + // semicolons, for each text style we want to apply. + write!(f, "\x1B[")?; + let mut written_anything = false; + + { + let mut write_char = |c| { + if written_anything { + write!(f, ";")?; + } + written_anything = true; + write!(f, "{}", c)?; + Ok(()) + }; + + if self.is_bold { + write_char('1')? + } + if self.is_dimmed { + write_char('2')? + } + if self.is_italic { + write_char('3')? + } + if self.is_underline { + write_char('4')? + } + if self.is_blink { + write_char('5')? + } + if self.is_reverse { + write_char('7')? + } + if self.is_hidden { + write_char('8')? + } + if self.is_strikethrough { + write_char('9')? + } + } + + // The foreground and background colors, if specified, need to be + // handled specially because the number codes are more complicated. + // (see `write_background_code` and `write_foreground_code`) + if let Some(bg) = self.background { + if written_anything { + write!(f, ";")?; + } + written_anything = true; + bg.write_background_code(f)?; + } + + if let Some(fg) = self.foreground { + if written_anything { + write!(f, ";")?; + } + fg.write_foreground_code(f)?; + } + + // All the codes end with an `m`, because reasons. + write!(f, "m")?; + + Ok(()) + } + + /// Write any bytes that go *after* a piece of text to the given writer. + fn write_suffix(&self, f: &mut W) -> Result<(), W::Error> { + if self.is_plain() { + Ok(()) + } else { + write!(f, "{}", RESET) + } + } +} + +/// The code to send to reset all styles and return to `Style::default()`. +pub static RESET: &str = "\x1B[0m"; + +impl Color { + fn write_foreground_code(&self, f: &mut W) -> Result<(), W::Error> { + match self { + Color::Black => write!(f, "30"), + Color::Red => write!(f, "31"), + Color::Green => write!(f, "32"), + Color::Yellow => write!(f, "33"), + Color::Blue => write!(f, "34"), + Color::Purple => write!(f, "35"), + Color::Magenta => write!(f, "35"), + Color::Cyan => write!(f, "36"), + Color::White => write!(f, "37"), + Color::Fixed(num) => write!(f, "38;5;{}", num), + Color::Rgb(r, g, b) => write!(f, "38;2;{};{};{}", r, g, b), + Color::DarkGray => write!(f, "90"), + Color::LightRed => write!(f, "91"), + Color::LightGreen => write!(f, "92"), + Color::LightYellow => write!(f, "93"), + Color::LightBlue => write!(f, "94"), + Color::LightPurple => write!(f, "95"), + Color::LightMagenta => write!(f, "95"), + Color::LightCyan => write!(f, "96"), + Color::LightGray => write!(f, "97"), + } + } + + fn write_background_code(&self, f: &mut W) -> Result<(), W::Error> { + match self { + Color::Black => write!(f, "40"), + Color::Red => write!(f, "41"), + Color::Green => write!(f, "42"), + Color::Yellow => write!(f, "43"), + Color::Blue => write!(f, "44"), + Color::Purple => write!(f, "45"), + Color::Magenta => write!(f, "45"), + Color::Cyan => write!(f, "46"), + Color::White => write!(f, "47"), + Color::Fixed(num) => write!(f, "48;5;{}", num), + Color::Rgb(r, g, b) => write!(f, "48;2;{};{};{}", r, g, b), + Color::DarkGray => write!(f, "100"), + Color::LightRed => write!(f, "101"), + Color::LightGreen => write!(f, "102"), + Color::LightYellow => write!(f, "103"), + Color::LightBlue => write!(f, "104"), + Color::LightPurple => write!(f, "105"), + Color::LightMagenta => write!(f, "105"), + Color::LightCyan => write!(f, "106"), + Color::LightGray => write!(f, "107"), + } + } +} + +/// Like `ANSIString`, but only displays the style prefix. +/// +/// This type implements the `Display` trait, meaning it can be written to a +/// `std::fmt` formatting without doing any extra allocation, and written to a +/// string with the `.to_string()` method. For examples, see +/// [`Style::prefix`](struct.Style.html#method.prefix). +#[derive(Clone, Copy, Debug)] +pub struct Prefix(Style); + +/// Like `ANSIString`, but only displays the difference between two +/// styles. +/// +/// This type implements the `Display` trait, meaning it can be written to a +/// `std::fmt` formatting without doing any extra allocation, and written to a +/// string with the `.to_string()` method. For examples, see +/// [`Style::infix`](struct.Style.html#method.infix). +#[derive(Clone, Copy, Debug)] +pub struct Infix(Style, Style); + +/// Like `ANSIString`, but only displays the style suffix. +/// +/// This type implements the `Display` trait, meaning it can be written to a +/// `std::fmt` formatting without doing any extra allocation, and written to a +/// string with the `.to_string()` method. For examples, see +/// [`Style::suffix`](struct.Style.html#method.suffix). +#[derive(Clone, Copy, Debug)] +pub struct Suffix(Style); + +impl Style { + /// The prefix bytes for this style. These are the bytes that tell the + /// terminal to use a different color or font style. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color::Blue}; + /// + /// let style = Style::default().bold(); + /// assert_eq!("\x1b[1m", + /// style.prefix().to_string()); + /// + /// let style = Blue.bold(); + /// assert_eq!("\x1b[1;34m", + /// style.prefix().to_string()); + /// + /// let style = Style::default(); + /// assert_eq!("", + /// style.prefix().to_string()); + /// ``` + pub fn prefix(self) -> Prefix { + Prefix(self) + } + + /// The infix bytes between this style and `next` style. These are the bytes + /// that tell the terminal to change the style to `next`. These may include + /// a reset followed by the next color and style, depending on the two styles. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color::Green}; + /// + /// let style = Style::default().bold(); + /// assert_eq!("\x1b[32m", + /// style.infix(Green.bold()).to_string()); + /// + /// let style = Green.normal(); + /// assert_eq!("\x1b[1m", + /// style.infix(Green.bold()).to_string()); + /// + /// let style = Style::default(); + /// assert_eq!("", + /// style.infix(style).to_string()); + /// ``` + pub fn infix(self, next: Style) -> Infix { + Infix(self, next) + } + + /// The suffix for this style. These are the bytes that tell the terminal + /// to reset back to its normal color and font style. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color::Green}; + /// + /// let style = Style::default().bold(); + /// assert_eq!("\x1b[0m", + /// style.suffix().to_string()); + /// + /// let style = Green.normal().bold(); + /// assert_eq!("\x1b[0m", + /// style.suffix().to_string()); + /// + /// let style = Style::default(); + /// assert_eq!("", + /// style.suffix().to_string()); + /// ``` + pub fn suffix(self) -> Suffix { + Suffix(self) + } +} + +impl Color { + /// The prefix bytes for this color as a `Style`. These are the bytes + /// that tell the terminal to use a different color or font style. + /// + /// See also [`Style::prefix`](struct.Style.html#method.prefix). + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color::Green; + /// + /// assert_eq!("\x1b[0m", + /// Green.suffix().to_string()); + /// ``` + pub fn prefix(self) -> Prefix { + Prefix(self.normal()) + } + + /// The infix bytes between this color and `next` color. These are the bytes + /// that tell the terminal to use the `next` color, or to do nothing if + /// the two colors are equal. + /// + /// See also [`Style::infix`](struct.Style.html#method.infix). + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color::{Red, Yellow}; + /// + /// assert_eq!("\x1b[33m", + /// Red.infix(Yellow).to_string()); + /// ``` + pub fn infix(self, next: Color) -> Infix { + Infix(self.normal(), next.normal()) + } + + /// The suffix for this color as a `Style`. These are the bytes that + /// tell the terminal to reset back to its normal color and font style. + /// + /// See also [`Style::suffix`](struct.Style.html#method.suffix). + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color::Purple; + /// + /// assert_eq!("\x1b[0m", + /// Purple.suffix().to_string()); + /// ``` + pub fn suffix(self) -> Suffix { + Suffix(self.normal()) + } +} + +impl fmt::Display for Prefix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f: &mut dyn fmt::Write = f; + self.0.write_prefix(f) + } +} + +impl fmt::Display for Infix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use crate::difference::Difference; + + match Difference::between(&self.0, &self.1) { + Difference::ExtraStyles(style) => { + let f: &mut dyn fmt::Write = f; + style.write_prefix(f) + } + Difference::Reset => { + let f: &mut dyn fmt::Write = f; + write!(f, "{}{}", RESET, self.1.prefix()) + } + Difference::Empty => { + Ok(()) // nothing to write + } + } + } +} + +impl fmt::Display for Suffix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f: &mut dyn fmt::Write = f; + self.0.write_suffix(f) + } +} + +#[cfg(test)] +mod test { + use crate::style::Color::*; + use crate::style::Style; + + macro_rules! test { + ($name: ident: $style: expr; $input: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($style.paint($input).to_string(), $result.to_string()); + + let mut v = Vec::new(); + $style.paint($input.as_bytes()).write_to(&mut v).unwrap(); + assert_eq!(v.as_slice(), $result.as_bytes()); + } + }; + } + + test!(plain: Style::default(); "text/plain" => "text/plain"); + test!(red: Red; "hi" => "\x1B[31mhi\x1B[0m"); + test!(black: Black.normal(); "hi" => "\x1B[30mhi\x1B[0m"); + test!(yellow_bold: Yellow.bold(); "hi" => "\x1B[1;33mhi\x1B[0m"); + test!(yellow_bold_2: Yellow.normal().bold(); "hi" => "\x1B[1;33mhi\x1B[0m"); + test!(blue_underline: Blue.underline(); "hi" => "\x1B[4;34mhi\x1B[0m"); + test!(green_bold_ul: Green.bold().underline(); "hi" => "\x1B[1;4;32mhi\x1B[0m"); + test!(green_bold_ul_2: Green.underline().bold(); "hi" => "\x1B[1;4;32mhi\x1B[0m"); + test!(purple_on_white: Purple.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(purple_on_white_2: Purple.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(yellow_on_blue: Style::new().on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); + test!(magenta_on_white: Magenta.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(magenta_on_white_2: Magenta.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(yellow_on_blue_2: Cyan.on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); + test!(cyan_bold_on_white: Cyan.bold().on(White); "hi" => "\x1B[1;47;36mhi\x1B[0m"); + test!(cyan_ul_on_white: Cyan.underline().on(White); "hi" => "\x1B[4;47;36mhi\x1B[0m"); + test!(cyan_bold_ul_on_white: Cyan.bold().underline().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m"); + test!(cyan_ul_bold_on_white: Cyan.underline().bold().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m"); + test!(fixed: Fixed(100); "hi" => "\x1B[38;5;100mhi\x1B[0m"); + test!(fixed_on_purple: Fixed(100).on(Purple); "hi" => "\x1B[45;38;5;100mhi\x1B[0m"); + test!(fixed_on_fixed: Fixed(100).on(Fixed(200)); "hi" => "\x1B[48;5;200;38;5;100mhi\x1B[0m"); + test!(rgb: Rgb(70,130,180); "hi" => "\x1B[38;2;70;130;180mhi\x1B[0m"); + test!(rgb_on_blue: Rgb(70,130,180).on(Blue); "hi" => "\x1B[44;38;2;70;130;180mhi\x1B[0m"); + test!(blue_on_rgb: Blue.on(Rgb(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m"); + test!(rgb_on_rgb: Rgb(70,130,180).on(Rgb(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m"); + test!(bold: Style::new().bold(); "hi" => "\x1B[1mhi\x1B[0m"); + test!(underline: Style::new().underline(); "hi" => "\x1B[4mhi\x1B[0m"); + test!(bunderline: Style::new().bold().underline(); "hi" => "\x1B[1;4mhi\x1B[0m"); + test!(dimmed: Style::new().dimmed(); "hi" => "\x1B[2mhi\x1B[0m"); + test!(italic: Style::new().italic(); "hi" => "\x1B[3mhi\x1B[0m"); + test!(blink: Style::new().blink(); "hi" => "\x1B[5mhi\x1B[0m"); + test!(reverse: Style::new().reverse(); "hi" => "\x1B[7mhi\x1B[0m"); + test!(hidden: Style::new().hidden(); "hi" => "\x1B[8mhi\x1B[0m"); + test!(stricken: Style::new().strikethrough(); "hi" => "\x1B[9mhi\x1B[0m"); + test!(lr_on_lr: LightRed.on(LightRed); "hi" => "\x1B[101;91mhi\x1B[0m"); + + #[test] + fn test_infix() { + assert_eq!( + Style::new().dimmed().infix(Style::new()).to_string(), + "\x1B[0m" + ); + assert_eq!( + White.dimmed().infix(White.normal()).to_string(), + "\x1B[0m\x1B[37m" + ); + assert_eq!(White.normal().infix(White.bold()).to_string(), "\x1B[1m"); + assert_eq!(White.normal().infix(Blue.normal()).to_string(), "\x1B[34m"); + assert_eq!(Blue.bold().infix(Blue.bold()).to_string(), ""); + } +} diff --git a/crates/nu-ansi-term/src/debug.rs b/crates/nu-ansi-term/src/debug.rs new file mode 100644 index 0000000000..1dcde52bec --- /dev/null +++ b/crates/nu-ansi-term/src/debug.rs @@ -0,0 +1,152 @@ +use crate::style::Style; +use std::fmt; + +/// Styles have a special `Debug` implementation that only shows the fields that +/// are set. Fields that haven’t been touched aren’t included in the output. +/// +/// This behaviour gets bypassed when using the alternate formatting mode +/// `format!("{:#?}")`. +/// +/// use nu_ansi_term::Color::{Red, Blue}; +/// assert_eq!("Style { fg(Red), on(Blue), bold, italic }", +/// format!("{:?}", Red.on(Blue).bold().italic())); +impl fmt::Debug for Style { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + if fmt.alternate() { + fmt.debug_struct("Style") + .field("foreground", &self.foreground) + .field("background", &self.background) + .field("blink", &self.is_blink) + .field("bold", &self.is_bold) + .field("dimmed", &self.is_dimmed) + .field("hidden", &self.is_hidden) + .field("italic", &self.is_italic) + .field("reverse", &self.is_reverse) + .field("strikethrough", &self.is_strikethrough) + .field("underline", &self.is_underline) + .finish() + } else if self.is_plain() { + fmt.write_str("Style {}") + } else { + fmt.write_str("Style { ")?; + + let mut written_anything = false; + + if let Some(fg) = self.foreground { + if written_anything { + fmt.write_str(", ")? + } + written_anything = true; + write!(fmt, "fg({:?})", fg)? + } + + if let Some(bg) = self.background { + if written_anything { + fmt.write_str(", ")? + } + written_anything = true; + write!(fmt, "on({:?})", bg)? + } + + { + let mut write_flag = |name| { + if written_anything { + fmt.write_str(", ")? + } + written_anything = true; + fmt.write_str(name) + }; + + if self.is_blink { + write_flag("blink")? + } + if self.is_bold { + write_flag("bold")? + } + if self.is_dimmed { + write_flag("dimmed")? + } + if self.is_hidden { + write_flag("hidden")? + } + if self.is_italic { + write_flag("italic")? + } + if self.is_reverse { + write_flag("reverse")? + } + if self.is_strikethrough { + write_flag("strikethrough")? + } + if self.is_underline { + write_flag("underline")? + } + } + + write!(fmt, " }}") + } + } +} + +#[cfg(test)] +mod test { + use crate::style::Color::*; + use crate::style::Style; + + fn style() -> Style { + Style::new() + } + + macro_rules! test { + ($name: ident: $obj: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($result, format!("{:?}", $obj)); + } + }; + } + + test!(empty: style() => "Style {}"); + test!(bold: style().bold() => "Style { bold }"); + test!(italic: style().italic() => "Style { italic }"); + test!(both: style().bold().italic() => "Style { bold, italic }"); + + test!(red: Red.normal() => "Style { fg(Red) }"); + test!(redblue: Red.normal().on(Rgb(3, 2, 4)) => "Style { fg(Red), on(Rgb(3, 2, 4)) }"); + + test!(everything: + Red.on(Blue).blink().bold().dimmed().hidden().italic().reverse().strikethrough().underline() => + "Style { fg(Red), on(Blue), blink, bold, dimmed, hidden, italic, reverse, strikethrough, underline }"); + + #[test] + fn long_and_detailed() { + extern crate regex; + let expected_debug = "Style { fg(Blue), bold }"; + let expected_pretty_repat = r##"(?x) + Style\s+\{\s+ + foreground:\s+Some\(\s+ + Blue,?\s+ + \),\s+ + background:\s+None,\s+ + blink:\s+false,\s+ + bold:\s+true,\s+ + dimmed:\s+false,\s+ + hidden:\s+false,\s+ + italic:\s+false,\s+ + reverse:\s+false,\s+ + strikethrough:\s+ + false,\s+ + underline:\s+false,?\s+ + \}"##; + let re = regex::Regex::new(expected_pretty_repat).unwrap(); + + let style = Blue.bold(); + let style_fmt_debug = format!("{:?}", style); + let style_fmt_pretty = format!("{:#?}", style); + println!("style_fmt_debug:\n{}", style_fmt_debug); + println!("style_fmt_pretty:\n{}", style_fmt_pretty); + + assert_eq!(expected_debug, style_fmt_debug); + assert!(re.is_match(&style_fmt_pretty)); + } +} diff --git a/crates/nu-ansi-term/src/difference.rs b/crates/nu-ansi-term/src/difference.rs new file mode 100644 index 0000000000..beee8ea253 --- /dev/null +++ b/crates/nu-ansi-term/src/difference.rs @@ -0,0 +1,174 @@ +use super::Style; + +/// When printing out one colored string followed by another, use one of +/// these rules to figure out which *extra* control codes need to be sent. +#[derive(PartialEq, Clone, Copy, Debug)] +pub enum Difference { + /// Print out the control codes specified by this style to end up looking + /// like the second string's styles. + ExtraStyles(Style), + + /// Converting between these two is impossible, so just send a reset + /// command and then the second string's styles. + Reset, + + /// The before style is exactly the same as the after style, so no further + /// control codes need to be printed. + Empty, +} + +impl Difference { + /// Compute the 'style difference' required to turn an existing style into + /// the given, second style. + /// + /// For example, to turn green text into green bold text, it's redundant + /// to write a reset command then a second green+bold command, instead of + /// just writing one bold command. This method should see that both styles + /// use the foreground color green, and reduce it to a single command. + /// + /// This method returns an enum value because it's not actually always + /// possible to turn one style into another: for example, text could be + /// made bold and underlined, but you can't remove the bold property + /// without also removing the underline property. So when this has to + /// happen, this function returns None, meaning that the entire set of + /// styles should be reset and begun again. + pub fn between(first: &Style, next: &Style) -> Difference { + use self::Difference::*; + + // XXX(Havvy): This algorithm is kind of hard to replicate without + // having the Plain/Foreground enum variants, so I'm just leaving + // it commented out for now, and defaulting to Reset. + + if first == next { + return Empty; + } + + // Cannot un-bold, so must Reset. + if first.is_bold && !next.is_bold { + return Reset; + } + + if first.is_dimmed && !next.is_dimmed { + return Reset; + } + + if first.is_italic && !next.is_italic { + return Reset; + } + + // Cannot un-underline, so must Reset. + if first.is_underline && !next.is_underline { + return Reset; + } + + if first.is_blink && !next.is_blink { + return Reset; + } + + if first.is_reverse && !next.is_reverse { + return Reset; + } + + if first.is_hidden && !next.is_hidden { + return Reset; + } + + if first.is_strikethrough && !next.is_strikethrough { + return Reset; + } + + // Cannot go from foreground to no foreground, so must Reset. + if first.foreground.is_some() && next.foreground.is_none() { + return Reset; + } + + // Cannot go from background to no background, so must Reset. + if first.background.is_some() && next.background.is_none() { + return Reset; + } + + let mut extra_styles = Style::default(); + + if first.is_bold != next.is_bold { + extra_styles.is_bold = true; + } + + if first.is_dimmed != next.is_dimmed { + extra_styles.is_dimmed = true; + } + + if first.is_italic != next.is_italic { + extra_styles.is_italic = true; + } + + if first.is_underline != next.is_underline { + extra_styles.is_underline = true; + } + + if first.is_blink != next.is_blink { + extra_styles.is_blink = true; + } + + if first.is_reverse != next.is_reverse { + extra_styles.is_reverse = true; + } + + if first.is_hidden != next.is_hidden { + extra_styles.is_hidden = true; + } + + if first.is_strikethrough != next.is_strikethrough { + extra_styles.is_strikethrough = true; + } + + if first.foreground != next.foreground { + extra_styles.foreground = next.foreground; + } + + if first.background != next.background { + extra_styles.background = next.background; + } + + ExtraStyles(extra_styles) + } +} + +#[cfg(test)] +mod test { + use super::Difference::*; + use super::*; + use crate::style::Color::*; + use crate::style::Style; + + fn style() -> Style { + Style::new() + } + + macro_rules! test { + ($name: ident: $first: expr; $next: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($result, Difference::between(&$first, &$next)); + } + }; + } + + test!(nothing: Green.normal(); Green.normal() => Empty); + test!(uppercase: Green.normal(); Green.bold() => ExtraStyles(style().bold())); + test!(lowercase: Green.bold(); Green.normal() => Reset); + test!(nothing2: Green.bold(); Green.bold() => Empty); + + test!(color_change: Red.normal(); Blue.normal() => ExtraStyles(Blue.normal())); + + test!(addition_of_blink: style(); style().blink() => ExtraStyles(style().blink())); + test!(addition_of_dimmed: style(); style().dimmed() => ExtraStyles(style().dimmed())); + test!(addition_of_hidden: style(); style().hidden() => ExtraStyles(style().hidden())); + test!(addition_of_reverse: style(); style().reverse() => ExtraStyles(style().reverse())); + test!(addition_of_strikethrough: style(); style().strikethrough() => ExtraStyles(style().strikethrough())); + + test!(removal_of_strikethrough: style().strikethrough(); style() => Reset); + test!(removal_of_reverse: style().reverse(); style() => Reset); + test!(removal_of_hidden: style().hidden(); style() => Reset); + test!(removal_of_dimmed: style().dimmed(); style() => Reset); + test!(removal_of_blink: style().blink(); style() => Reset); +} diff --git a/crates/nu-ansi-term/src/display.rs b/crates/nu-ansi-term/src/display.rs new file mode 100644 index 0000000000..db5221f353 --- /dev/null +++ b/crates/nu-ansi-term/src/display.rs @@ -0,0 +1,303 @@ +use crate::ansi::RESET; +use crate::difference::Difference; +use crate::style::{Color, Style}; +use crate::write::AnyWrite; +use std::borrow::Cow; +use std::fmt; +use std::io; +use std::ops::Deref; + +/// An `ANSIGenericString` includes a generic string type and a `Style` to +/// display that string. `ANSIString` and `ANSIByteString` are aliases for +/// this type on `str` and `\[u8]`, respectively. +#[derive(PartialEq, Debug)] +pub struct AnsiGenericString<'a, S: 'a + ToOwned + ?Sized> +where + ::Owned: fmt::Debug, +{ + style: Style, + string: Cow<'a, S>, +} + +/// Cloning an `ANSIGenericString` will clone its underlying string. +/// +/// # Examples +/// +/// ``` +/// use nu_ansi_term::ANSIString; +/// +/// let plain_string = ANSIString::from("a plain string"); +/// let clone_string = plain_string.clone(); +/// assert_eq!(clone_string, plain_string); +/// ``` +impl<'a, S: 'a + ToOwned + ?Sized> Clone for AnsiGenericString<'a, S> +where + ::Owned: fmt::Debug, +{ + fn clone(&self) -> AnsiGenericString<'a, S> { + AnsiGenericString { + style: self.style, + string: self.string.clone(), + } + } +} + +// You might think that the hand-written Clone impl above is the same as the +// one that gets generated with #[derive]. But it’s not *quite* the same! +// +// `str` is not Clone, and the derived Clone implementation puts a Clone +// constraint on the S type parameter (generated using --pretty=expanded): +// +// ↓_________________↓ +// impl <'a, S: ::std::clone::Clone + 'a + ToOwned + ?Sized> ::std::clone::Clone +// for ANSIGenericString<'a, S> where +// ::Owned: fmt::Debug { ... } +// +// This resulted in compile errors when you tried to derive Clone on a type +// that used it: +// +// #[derive(PartialEq, Debug, Clone, Default)] +// pub struct TextCellContents(Vec>); +// ^^^^^^^^^^^^^^^^^^^^^^^^^ +// error[E0277]: the trait `std::clone::Clone` is not implemented for `str` +// +// The hand-written impl above can ignore that constraint and still compile. + +/// An ANSI String is a string coupled with the `Style` to display it +/// in a terminal. +/// +/// Although not technically a string itself, it can be turned into +/// one with the `to_string` method. +/// +/// # Examples +/// +/// ``` +/// use nu_ansi_term::ANSIString; +/// use nu_ansi_term::Color::Red; +/// +/// let red_string = Red.paint("a red string"); +/// println!("{}", red_string); +/// ``` +/// +/// ``` +/// use nu_ansi_term::ANSIString; +/// +/// let plain_string = ANSIString::from("a plain string"); +/// assert_eq!(&*plain_string, "a plain string"); +/// ``` +pub type AnsiString<'a> = AnsiGenericString<'a, str>; + +/// An `AnsiByteString` represents a formatted series of bytes. Use +/// `AnsiByteString` when styling text with an unknown encoding. +pub type AnsiByteString<'a> = AnsiGenericString<'a, [u8]>; + +impl<'a, I, S: 'a + ToOwned + ?Sized> From for AnsiGenericString<'a, S> +where + I: Into>, + ::Owned: fmt::Debug, +{ + fn from(input: I) -> AnsiGenericString<'a, S> { + AnsiGenericString { + string: input.into(), + style: Style::default(), + } + } +} + +impl<'a, S: 'a + ToOwned + ?Sized> AnsiGenericString<'a, S> +where + ::Owned: fmt::Debug, +{ + /// Directly access the style + pub fn style_ref(&self) -> &Style { + &self.style + } + + /// Directly access the style mutably + pub fn style_ref_mut(&mut self) -> &mut Style { + &mut self.style + } +} + +impl<'a, S: 'a + ToOwned + ?Sized> Deref for AnsiGenericString<'a, S> +where + ::Owned: fmt::Debug, +{ + type Target = S; + + fn deref(&self) -> &S { + self.string.deref() + } +} + +/// A set of `AnsiGenericStrings`s collected together, in order to be +/// written with a minimum of control characters. +#[derive(Debug, PartialEq)] +pub struct AnsiGenericStrings<'a, S: 'a + ToOwned + ?Sized>(pub &'a [AnsiGenericString<'a, S>]) +where + ::Owned: fmt::Debug, + S: PartialEq; + +/// A set of `AnsiString`s collected together, in order to be written with a +/// minimum of control characters. +pub type AnsiStrings<'a> = AnsiGenericStrings<'a, str>; + +/// A function to construct an `AnsiStrings` instance. +#[allow(non_snake_case)] +pub fn AnsiStrings<'a>(arg: &'a [AnsiString<'a>]) -> AnsiStrings<'a> { + AnsiGenericStrings(arg) +} + +/// A set of `AnsiByteString`s collected together, in order to be +/// written with a minimum of control characters. +pub type AnsiByteStrings<'a> = AnsiGenericStrings<'a, [u8]>; + +/// A function to construct an `ANSIByteStrings` instance. +#[allow(non_snake_case)] +pub fn ANSIByteStrings<'a>(arg: &'a [AnsiByteString<'a>]) -> AnsiByteStrings<'a> { + AnsiGenericStrings(arg) +} + +// ---- paint functions ---- + +impl Style { + /// Paints the given text with this color, returning an ANSI string. + #[must_use] + pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> AnsiGenericString<'a, S> + where + I: Into>, + ::Owned: fmt::Debug, + { + AnsiGenericString { + string: input.into(), + style: self, + } + } +} + +impl Color { + /// Paints the given text with this color, returning an ANSI string. + /// This is a short-cut so you don’t have to use `Blue.normal()` just + /// to get blue text. + /// + /// ``` + /// use nu_ansi_term::Color::Blue; + /// println!("{}", Blue.paint("da ba dee")); + /// ``` + #[must_use] + pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> AnsiGenericString<'a, S> + where + I: Into>, + ::Owned: fmt::Debug, + { + AnsiGenericString { + string: input.into(), + style: self.normal(), + } + } +} + +// ---- writers for individual ANSI strings ---- + +impl<'a> fmt::Display for AnsiString<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let w: &mut dyn fmt::Write = f; + self.write_to_any(w) + } +} + +impl<'a> AnsiByteString<'a> { + /// Write an `ANSIByteString` to an `io::Write`. This writes the escape + /// sequences for the associated `Style` around the bytes. + pub fn write_to(&self, w: &mut W) -> io::Result<()> { + let w: &mut dyn io::Write = w; + self.write_to_any(w) + } +} + +impl<'a, S: 'a + ToOwned + ?Sized> AnsiGenericString<'a, S> +where + ::Owned: fmt::Debug, + &'a S: AsRef<[u8]>, +{ + fn write_to_any + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> { + write!(w, "{}", self.style.prefix())?; + w.write_str(self.string.as_ref())?; + write!(w, "{}", self.style.suffix()) + } +} + +// ---- writers for combined ANSI strings ---- + +impl<'a> fmt::Display for AnsiStrings<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f: &mut dyn fmt::Write = f; + self.write_to_any(f) + } +} + +impl<'a> AnsiByteStrings<'a> { + /// Write `ANSIByteStrings` to an `io::Write`. This writes the minimal + /// escape sequences for the associated `Style`s around each set of + /// bytes. + pub fn write_to(&self, w: &mut W) -> io::Result<()> { + let w: &mut dyn io::Write = w; + self.write_to_any(w) + } +} + +impl<'a, S: 'a + ToOwned + ?Sized + PartialEq> AnsiGenericStrings<'a, S> +where + ::Owned: fmt::Debug, + &'a S: AsRef<[u8]>, +{ + fn write_to_any + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> { + use self::Difference::*; + + let first = match self.0.first() { + None => return Ok(()), + Some(f) => f, + }; + + write!(w, "{}", first.style.prefix())?; + w.write_str(first.string.as_ref())?; + + for window in self.0.windows(2) { + match Difference::between(&window[0].style, &window[1].style) { + ExtraStyles(style) => write!(w, "{}", style.prefix())?, + Reset => write!(w, "{}{}", RESET, window[1].style.prefix())?, + Empty => { /* Do nothing! */ } + } + + w.write_str(&window[1].string)?; + } + + // Write the final reset string after all of the ANSIStrings have been + // written, *except* if the last one has no styles, because it would + // have already been written by this point. + if let Some(last) = self.0.last() { + if !last.style.is_plain() { + write!(w, "{}", RESET)?; + } + } + + Ok(()) + } +} + +// ---- tests ---- + +#[cfg(test)] +mod tests { + pub use super::super::AnsiStrings; + pub use crate::style::Color::*; + pub use crate::style::Style; + + #[test] + fn no_control_codes_for_plain() { + let one = Style::default().paint("one"); + let two = Style::default().paint("two"); + let output = AnsiStrings(&[one, two]).to_string(); + assert_eq!(output, "onetwo"); + } +} diff --git a/crates/nu-ansi-term/src/gradient.rs b/crates/nu-ansi-term/src/gradient.rs new file mode 100644 index 0000000000..a0d94c8cd3 --- /dev/null +++ b/crates/nu-ansi-term/src/gradient.rs @@ -0,0 +1,105 @@ +use crate::{rgb::Rgb, Color}; + +/// Linear color gradient between two color stops +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Gradient { + /// Start Color of Gradient + pub start: Rgb, + + /// End Color of Gradient + pub end: Rgb, +} + +impl Gradient { + /// Creates a new [Gradient] with two [Rgb] colors, `start` and `end` + #[inline] + pub const fn new(start: Rgb, end: Rgb) -> Self { + Self { start, end } + } + pub const fn from_color_rgb(start: Color, end: Color) -> Self { + let start_grad = match start { + Color::Rgb(r, g, b) => Rgb { r, g, b }, + _ => Rgb { r: 0, g: 0, b: 0 }, + }; + let end_grad = match end { + Color::Rgb(r, g, b) => Rgb { r, g, b }, + _ => Rgb { r: 0, g: 0, b: 0 }, + }; + + Self { + start: start_grad, + end: end_grad, + } + } + + /// Computes the [Rgb] color between `start` and `end` for `t` + pub fn at(&self, t: f32) -> Rgb { + self.start.lerp(self.end, t) + } + + /// Returns the reverse of `self` + #[inline] + pub const fn reverse(&self) -> Self { + Self::new(self.end, self.start) + } + + #[allow(dead_code)] + pub fn build(&self, text: &str, target: TargetGround) -> String { + let delta = 1.0 / text.len() as f32; + let mut result = text.char_indices().fold(String::new(), |mut acc, (i, c)| { + let temp = format!( + "\x1B[{}m{}", + self.at(i as f32 * delta).ansi_color_code(target), + c + ); + acc.push_str(&temp); + acc + }); + + result.push_str("\x1B[0m"); + result + } +} + +#[allow(dead_code)] +pub fn build_all_gradient_text(text: &str, foreground: Gradient, background: Gradient) -> String { + let delta = 1.0 / text.len() as f32; + let mut result = text.char_indices().fold(String::new(), |mut acc, (i, c)| { + let step = i as f32 * delta; + let temp = format!( + "\x1B[{};{}m{}", + foreground + .at(step) + .ansi_color_code(TargetGround::Foreground), + background + .at(step) + .ansi_color_code(TargetGround::Background), + c + ); + acc.push_str(&temp); + acc + }); + + result.push_str("\x1B[0m"); + result +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TargetGround { + Foreground, + Background, +} + +impl TargetGround { + #[inline] + pub const fn code(&self) -> u8 { + match self { + Self::Foreground => 30, + Self::Background => 40, + } + } +} + +pub trait ANSIColorCode { + fn ansi_color_code(&self, target: TargetGround) -> String; +} diff --git a/crates/nu-ansi-term/src/lib.rs b/crates/nu-ansi-term/src/lib.rs new file mode 100644 index 0000000000..d33b9bb52e --- /dev/null +++ b/crates/nu-ansi-term/src/lib.rs @@ -0,0 +1,272 @@ +//! This is a library for controlling colors and formatting, such as +//! red bold text or blue underlined text, on ANSI terminals. +//! +//! +//! ## Basic usage +//! +//! There are three main types in this crate that you need to be +//! concerned with: [`ANSIString`], [`Style`], and [`Color`]. +//! +//! A `Style` holds stylistic information: foreground and background colors, +//! whether the text should be bold, or blinking, or other properties. The +//! [`Color`] enum represents the available colors. And an [`ANSIString`] is a +//! string paired with a [`Style`]. +//! +//! [`Color`] is also available as an alias to `Color`. +//! +//! To format a string, call the `paint` method on a `Style` or a `Color`, +//! passing in the string you want to format as the argument. For example, +//! here’s how to get some red text: +//! +//! ``` +//! use nu_ansi_term::Color::Red; +//! +//! println!("This is in red: {}", Red.paint("a red string")); +//! ``` +//! +//! It’s important to note that the `paint` method does *not* actually return a +//! string with the ANSI control characters surrounding it. Instead, it returns +//! an [`ANSIString`] value that has a [`Display`] implementation that, when +//! formatted, returns the characters. This allows strings to be printed with a +//! minimum of [`String`] allocations being performed behind the scenes. +//! +//! If you *do* want to get at the escape codes, then you can convert the +//! [`ANSIString`] to a string as you would any other `Display` value: +//! +//! ``` +//! use nu_ansi_term::Color::Red; +//! +//! let red_string = Red.paint("a red string").to_string(); +//! ``` +//! +//! +//! ## Bold, underline, background, and other styles +//! +//! For anything more complex than plain foreground color changes, you need to +//! construct `Style` values themselves, rather than beginning with a `Color`. +//! You can do this by chaining methods based on a new `Style`, created with +//! [`Style::new()`]. Each method creates a new style that has that specific +//! property set. For example: +//! +//! ``` +//! use nu_ansi_term::Style; +//! +//! println!("How about some {} and {}?", +//! Style::new().bold().paint("bold"), +//! Style::new().underline().paint("underline")); +//! ``` +//! +//! For brevity, these methods have also been implemented for `Color` values, +//! so you can give your styles a foreground color without having to begin with +//! an empty `Style` value: +//! +//! ``` +//! use nu_ansi_term::Color::{Blue, Yellow}; +//! +//! println!("Demonstrating {} and {}!", +//! Blue.bold().paint("blue bold"), +//! Yellow.underline().paint("yellow underline")); +//! +//! println!("Yellow on blue: {}", Yellow.on(Blue).paint("wow!")); +//! ``` +//! +//! The complete list of styles you can use are: [`bold`], [`dimmed`], [`italic`], +//! [`underline`], [`blink`], [`reverse`], [`hidden`], [`strikethrough`], and [`on`] for +//! background colors. +//! +//! In some cases, you may find it easier to change the foreground on an +//! existing `Style` rather than starting from the appropriate `Color`. +//! You can do this using the [`fg`] method: +//! +//! ``` +//! use nu_ansi_term::Style; +//! use nu_ansi_term::Color::{Blue, Cyan, Yellow}; +//! +//! println!("Yellow on blue: {}", Style::new().on(Blue).fg(Yellow).paint("yow!")); +//! println!("Also yellow on blue: {}", Cyan.on(Blue).fg(Yellow).paint("zow!")); +//! ``` +//! +//! You can turn a `Color` into a `Style` with the [`normal`] method. +//! This will produce the exact same `ANSIString` as if you just used the +//! `paint` method on the `Color` directly, but it’s useful in certain cases: +//! for example, you may have a method that returns `Styles`, and need to +//! represent both the β€œred bold” and β€œred, but not bold” styles with values of +//! the same type. The `Style` struct also has a [`Default`] implementation if you +//! want to have a style with *nothing* set. +//! +//! ``` +//! use nu_ansi_term::Style; +//! use nu_ansi_term::Color::Red; +//! +//! Red.normal().paint("yet another red string"); +//! Style::default().paint("a completely regular string"); +//! ``` +//! +//! +//! ## Extended colors +//! +//! You can access the extended range of 256 colors by using the `Color::Fixed` +//! variant, which takes an argument of the color number to use. This can be +//! included wherever you would use a `Color`: +//! +//! ``` +//! use nu_ansi_term::Color::Fixed; +//! +//! Fixed(134).paint("A sort of light purple"); +//! Fixed(221).on(Fixed(124)).paint("Mustard in the ketchup"); +//! ``` +//! +//! The first sixteen of these values are the same as the normal and bold +//! standard color variants. There’s nothing stopping you from using these as +//! `Fixed` colors instead, but there’s nothing to be gained by doing so +//! either. +//! +//! You can also access full 24-bit color by using the `Color::Rgb` variant, +//! which takes separate `u8` arguments for red, green, and blue: +//! +//! ``` +//! use nu_ansi_term::Color::Rgb; +//! +//! Rgb(70, 130, 180).paint("Steel blue"); +//! ``` +//! +//! ## Combining successive colored strings +//! +//! The benefit of writing ANSI escape codes to the terminal is that they +//! *stack*: you do not need to end every colored string with a reset code if +//! the text that follows it is of a similar style. For example, if you want to +//! have some blue text followed by some blue bold text, it’s possible to send +//! the ANSI code for blue, followed by the ANSI code for bold, and finishing +//! with a reset code without having to have an extra one between the two +//! strings. +//! +//! This crate can optimise the ANSI codes that get printed in situations like +//! this, making life easier for your terminal renderer. The [`ANSIStrings`] +//! type takes a slice of several [`ANSIString`] values, and will iterate over +//! each of them, printing only the codes for the styles that need to be updated +//! as part of its formatting routine. +//! +//! The following code snippet uses this to enclose a binary number displayed in +//! red bold text inside some red, but not bold, brackets: +//! +//! ``` +//! use nu_ansi_term::Color::Red; +//! use nu_ansi_term::{ANSIString, ANSIStrings}; +//! +//! let some_value = format!("{:b}", 42); +//! let strings: &[ANSIString<'static>] = &[ +//! Red.paint("["), +//! Red.bold().paint(some_value), +//! Red.paint("]"), +//! ]; +//! +//! println!("Value: {}", ANSIStrings(strings)); +//! ``` +//! +//! There are several things to note here. Firstly, the [`paint`] method can take +//! *either* an owned [`String`] or a borrowed [`&str`]. Internally, an [`ANSIString`] +//! holds a copy-on-write ([`Cow`]) string value to deal with both owned and +//! borrowed strings at the same time. This is used here to display a `String`, +//! the result of the `format!` call, using the same mechanism as some +//! statically-available `&str` slices. Secondly, that the [`ANSIStrings`] value +//! works in the same way as its singular counterpart, with a [`Display`] +//! implementation that only performs the formatting when required. +//! +//! ## Byte strings +//! +//! This library also supports formatting `\[u8]` byte strings; this supports +//! applications working with text in an unknown encoding. [`Style`] and +//! [`Color`] support painting `\[u8]` values, resulting in an [`ANSIByteString`]. +//! This type does not implement [`Display`], as it may not contain UTF-8, but +//! it does provide a method [`write_to`] to write the result to any value that +//! implements [`Write`]: +//! +//! ``` +//! use nu_ansi_term::Color::Green; +//! +//! Green.paint("user data".as_bytes()).write_to(&mut std::io::stdout()).unwrap(); +//! ``` +//! +//! Similarly, the type [`ANSIByteStrings`] supports writing a list of +//! [`ANSIByteString`] values with minimal escape sequences: +//! +//! ``` +//! use nu_ansi_term::Color::Green; +//! use nu_ansi_term::ANSIByteStrings; +//! +//! ANSIByteStrings(&[ +//! Green.paint("user data 1\n".as_bytes()), +//! Green.bold().paint("user data 2\n".as_bytes()), +//! ]).write_to(&mut std::io::stdout()).unwrap(); +//! ``` +//! +//! [`Cow`]: https://doc.rust-lang.org/std/borrow/enum.Cow.html +//! [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html +//! [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html +//! [`String`]: https://doc.rust-lang.org/std/string/struct.String.html +//! [`&str`]: https://doc.rust-lang.org/std/primitive.str.html +//! [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +//! [`Style`]: struct.Style.html +//! [`Style::new()`]: struct.Style.html#method.new +//! [`Color`]: enum.Color.html +//! [`Color`]: enum.Color.html +//! [`ANSIString`]: type.ANSIString.html +//! [`ANSIStrings`]: type.ANSIStrings.html +//! [`ANSIByteString`]: type.ANSIByteString.html +//! [`ANSIByteStrings`]: type.ANSIByteStrings.html +//! [`write_to`]: type.ANSIByteString.html#method.write_to +//! [`paint`]: type.ANSIByteString.html#method.write_to +//! [`normal`]: enum.Color.html#method.normal +//! +//! [`bold`]: struct.Style.html#method.bold +//! [`dimmed`]: struct.Style.html#method.dimmed +//! [`italic`]: struct.Style.html#method.italic +//! [`underline`]: struct.Style.html#method.underline +//! [`blink`]: struct.Style.html#method.blink +//! [`reverse`]: struct.Style.html#method.reverse +//! [`hidden`]: struct.Style.html#method.hidden +//! [`strikethrough`]: struct.Style.html#method.strikethrough +//! [`fg`]: struct.Style.html#method.fg +//! [`on`]: struct.Style.html#method.on + +#![crate_name = "nu_ansi_term"] +#![crate_type = "rlib"] +#![warn(missing_copy_implementations)] +// #![warn(missing_docs)] +#![warn(trivial_casts, trivial_numeric_casts)] +// #![warn(unused_extern_crates, unused_qualifications)] + +#[cfg(target_os = "windows")] +extern crate winapi; +#[cfg(test)] +#[macro_use] +extern crate doc_comment; + +#[cfg(test)] +doctest!("../README.md"); + +pub mod ansi; +pub use ansi::{Infix, Prefix, Suffix}; + +mod style; +pub use style::{Color, Style}; + +mod difference; +mod display; +pub use display::*; + +mod write; + +mod windows; +pub use windows::*; + +mod util; +pub use util::*; + +mod debug; + +pub mod gradient; +pub use gradient::*; + +mod rgb; +pub use rgb::*; diff --git a/crates/nu-ansi-term/src/rgb.rs b/crates/nu-ansi-term/src/rgb.rs new file mode 100644 index 0000000000..19475c36b0 --- /dev/null +++ b/crates/nu-ansi-term/src/rgb.rs @@ -0,0 +1,173 @@ +// Code liberally borrowed from here +// https://github.com/navierr/coloriz +use std::ops; +use std::u32; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Rgb { + /// Red + pub r: u8, + /// Green + pub g: u8, + /// Blue + pub b: u8, +} + +impl Rgb { + /// Creates a new [Rgb] color + #[inline] + pub const fn new(r: u8, g: u8, b: u8) -> Self { + Self { r, g, b } + } + + /// Creates a new [Rgb] color with a hex code + #[inline] + pub const fn from_hex(hex: u32) -> Self { + Self::new((hex >> 16) as u8, (hex >> 8) as u8, hex as u8) + } + + pub fn from_hex_string(hex: String) -> Self { + if hex.chars().count() == 8 && hex.starts_with("0x") { + // eprintln!("hex:{:?}", hex); + let (_, value_string) = hex.split_at(2); + // eprintln!("value_string:{:?}", value_string); + let int_val = u64::from_str_radix(value_string, 16); + match int_val { + Ok(num) => Self::new( + ((num & 0xff0000) >> 16) as u8, + ((num & 0xff00) >> 8) as u8, + (num & 0xff) as u8, + ), + // Don't fail, just make the color black + // Should we fail? + _ => Self::new(0, 0, 0), + } + } else { + // Don't fail, just make the color black. + // Should we fail? + Self::new(0, 0, 0) + } + } + + /// Creates a new [Rgb] color with three [f32] values + pub fn from_f32(r: f32, g: f32, b: f32) -> Self { + Self::new( + (r.clamp(0.0, 1.0) * 255.0) as u8, + (g.clamp(0.0, 1.0) * 255.0) as u8, + (b.clamp(0.0, 1.0) * 255.0) as u8, + ) + } + + /// Creates a grayscale [Rgb] color + #[inline] + pub const fn gray(x: u8) -> Self { + Self::new(x, x, x) + } + + /// Creates a grayscale [Rgb] color with a [f32] value + pub fn gray_f32(x: f32) -> Self { + Self::from_f32(x, x, x) + } + + /// Creates a new [Rgb] color from a [HSL] color + // pub fn from_hsl(hsl: HSL) -> Self { + // if hsl.s == 0.0 { + // return Self::gray_f32(hsl.l); + // } + + // let q = if hsl.l < 0.5 { + // hsl.l * (1.0 + hsl.s) + // } else { + // hsl.l + hsl.s - hsl.l * hsl.s + // }; + // let p = 2.0 * hsl.l - q; + // let h2c = |t: f32| { + // let t = t.clamp(0.0, 1.0); + // if 6.0 * t < 1.0 { + // p + 6.0 * (q - p) * t + // } else if t < 0.5 { + // q + // } else if 1.0 < 1.5 * t { + // p + 6.0 * (q - p) * (1.0 / 1.5 - t) + // } else { + // p + // } + // }; + + // Self::from_f32(h2c(hsl.h + 1.0 / 3.0), h2c(hsl.h), h2c(hsl.h - 1.0 / 3.0)) + // } + + /// Computes the linear interpolation between `self` and `other` for `t` + pub fn lerp(&self, other: Self, t: f32) -> Self { + let t = t.clamp(0.0, 1.0); + self * (1.0 - t) + other * t + } +} + +impl From<(u8, u8, u8)> for Rgb { + fn from((r, g, b): (u8, u8, u8)) -> Self { + Self::new(r, g, b) + } +} + +impl From<(f32, f32, f32)> for Rgb { + fn from((r, g, b): (f32, f32, f32)) -> Self { + Self::from_f32(r, g, b) + } +} + +use crate::ANSIColorCode; +use crate::TargetGround; +impl ANSIColorCode for Rgb { + fn ansi_color_code(&self, target: TargetGround) -> String { + format!("{};2;{};{};{}", target.code() + 8, self.r, self.g, self.b) + } +} + +overload::overload!( + (lhs: ?Rgb) + (rhs: ?Rgb) -> Rgb { + Rgb::new( + lhs.r.saturating_add(rhs.r), + lhs.g.saturating_add(rhs.g), + lhs.b.saturating_add(rhs.b) + ) + } +); + +overload::overload!( + (lhs: ?Rgb) - (rhs: ?Rgb) -> Rgb { + Rgb::new( + lhs.r.saturating_sub(rhs.r), + lhs.g.saturating_sub(rhs.g), + lhs.b.saturating_sub(rhs.b) + ) + } +); + +overload::overload!( + (lhs: ?Rgb) * (rhs: ?f32) -> Rgb { + Rgb::new( + (lhs.r as f32 * rhs.clamp(0.0, 1.0)) as u8, + (lhs.g as f32 * rhs.clamp(0.0, 1.0)) as u8, + (lhs.b as f32 * rhs.clamp(0.0, 1.0)) as u8 + ) + } +); + +overload::overload!( + (lhs: ?f32) * (rhs: ?Rgb) -> Rgb { + Rgb::new( + (rhs.r as f32 * lhs.clamp(0.0, 1.0)) as u8, + (rhs.g as f32 * lhs.clamp(0.0, 1.0)) as u8, + (rhs.b as f32 * lhs.clamp(0.0, 1.0)) as u8 + ) + } +); + +overload::overload!( + -(rgb: ?Rgb) -> Rgb { + Rgb::new( + 255 - rgb.r, + 255 - rgb.g, + 255 - rgb.b) + } +); diff --git a/crates/nu-ansi-term/src/style.rs b/crates/nu-ansi-term/src/style.rs new file mode 100644 index 0000000000..c4f1d7514f --- /dev/null +++ b/crates/nu-ansi-term/src/style.rs @@ -0,0 +1,626 @@ +/// A style is a collection of properties that can format a string +/// using ANSI escape codes. +/// +/// # Examples +/// +/// ``` +/// use nu_ansi_term::{Style, Color}; +/// +/// let style = Style::new().bold().on(Color::Black); +/// println!("{}", style.paint("Bold on black")); +/// ``` +#[derive(PartialEq, Clone, Copy)] +#[cfg_attr( + feature = "derive_serde_style", + derive(serde::Deserialize, serde::Serialize) +)] +pub struct Style { + /// The style's foreground color, if it has one. + pub foreground: Option, + + /// The style's background color, if it has one. + pub background: Option, + + /// Whether this style is bold. + pub is_bold: bool, + + /// Whether this style is dimmed. + pub is_dimmed: bool, + + /// Whether this style is italic. + pub is_italic: bool, + + /// Whether this style is underlined. + pub is_underline: bool, + + /// Whether this style is blinking. + pub is_blink: bool, + + /// Whether this style has reverse colors. + pub is_reverse: bool, + + /// Whether this style is hidden. + pub is_hidden: bool, + + /// Whether this style is struckthrough. + pub is_strikethrough: bool, +} + +impl Style { + /// Creates a new Style with no properties set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new(); + /// println!("{}", style.paint("hi")); + /// ``` + pub fn new() -> Style { + Style::default() + } + + /// Returns a `Style` with the bold property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().bold(); + /// println!("{}", style.paint("hey")); + /// ``` + pub fn bold(&self) -> Style { + Style { + is_bold: true, + ..*self + } + } + + /// Returns a `Style` with the dimmed property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().dimmed(); + /// println!("{}", style.paint("sup")); + /// ``` + pub fn dimmed(&self) -> Style { + Style { + is_dimmed: true, + ..*self + } + } + + /// Returns a `Style` with the italic property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().italic(); + /// println!("{}", style.paint("greetings")); + /// ``` + pub fn italic(&self) -> Style { + Style { + is_italic: true, + ..*self + } + } + + /// Returns a `Style` with the underline property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().underline(); + /// println!("{}", style.paint("salutations")); + /// ``` + pub fn underline(&self) -> Style { + Style { + is_underline: true, + ..*self + } + } + + /// Returns a `Style` with the blink property set. + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().blink(); + /// println!("{}", style.paint("wazzup")); + /// ``` + pub fn blink(&self) -> Style { + Style { + is_blink: true, + ..*self + } + } + + /// Returns a `Style` with the reverse property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().reverse(); + /// println!("{}", style.paint("aloha")); + /// ``` + pub fn reverse(&self) -> Style { + Style { + is_reverse: true, + ..*self + } + } + + /// Returns a `Style` with the hidden property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().hidden(); + /// println!("{}", style.paint("ahoy")); + /// ``` + pub fn hidden(&self) -> Style { + Style { + is_hidden: true, + ..*self + } + } + + /// Returns a `Style` with the strikethrough property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// let style = Style::new().strikethrough(); + /// println!("{}", style.paint("yo")); + /// ``` + pub fn strikethrough(&self) -> Style { + Style { + is_strikethrough: true, + ..*self + } + } + + /// Returns a `Style` with the foreground color property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color}; + /// + /// let style = Style::new().fg(Color::Yellow); + /// println!("{}", style.paint("hi")); + /// ``` + pub fn fg(&self, foreground: Color) -> Style { + Style { + foreground: Some(foreground), + ..*self + } + } + + /// Returns a `Style` with the background color property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::{Style, Color}; + /// + /// let style = Style::new().on(Color::Blue); + /// println!("{}", style.paint("eyyyy")); + /// ``` + pub fn on(&self, background: Color) -> Style { + Style { + background: Some(background), + ..*self + } + } + + /// Return true if this `Style` has no actual styles, and can be written + /// without any control characters. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Style; + /// + /// assert_eq!(true, Style::default().is_plain()); + /// assert_eq!(false, Style::default().bold().is_plain()); + /// ``` + pub fn is_plain(self) -> bool { + self == Style::default() + } +} + +impl Default for Style { + /// Returns a style with *no* properties set. Formatting text using this + /// style returns the exact same text. + /// + /// ``` + /// use nu_ansi_term::Style; + /// assert_eq!(None, Style::default().foreground); + /// assert_eq!(None, Style::default().background); + /// assert_eq!(false, Style::default().is_bold); + /// assert_eq!("txt", Style::default().paint("txt").to_string()); + /// ``` + fn default() -> Style { + Style { + foreground: None, + background: None, + is_bold: false, + is_dimmed: false, + is_italic: false, + is_underline: false, + is_blink: false, + is_reverse: false, + is_hidden: false, + is_strikethrough: false, + } + } +} + +// ---- colors ---- + +/// A color is one specific type of ANSI escape code, and can refer +/// to either the foreground or background color. +/// +/// These use the standard numeric sequences. +/// See +#[derive(PartialEq, Clone, Copy, Debug)] +#[cfg_attr( + feature = "derive_serde_style", + derive(serde::Deserialize, serde::Serialize) +)] +pub enum Color { + /// Color #0 (foreground code `30`, background code `40`). + /// + /// This is not necessarily the background color, and using it as one may + /// render the text hard to read on terminals with dark backgrounds. + Black, + + /// Color #0 (foreground code `90`, background code `100`). + DarkGray, + + /// Color #1 (foreground code `31`, background code `41`). + Red, + + /// Color #1 (foreground code `91`, background code `101`). + LightRed, + + /// Color #2 (foreground code `32`, background code `42`). + Green, + + /// Color #2 (foreground code `92`, background code `102`). + LightGreen, + + /// Color #3 (foreground code `33`, background code `43`). + Yellow, + + /// Color #3 (foreground code `93`, background code `103`). + LightYellow, + + /// Color #4 (foreground code `34`, background code `44`). + Blue, + + /// Color #4 (foreground code `94`, background code `104`). + LightBlue, + + /// Color #5 (foreground code `35`, background code `45`). + Purple, + + /// Color #5 (foreground code `95`, background code `105`). + LightPurple, + + /// Color #5 (foreground code `35`, background code `45`). + Magenta, + + /// Color #5 (foreground code `95`, background code `105`). + LightMagenta, + + /// Color #6 (foreground code `36`, background code `46`). + Cyan, + + /// Color #6 (foreground code `96`, background code `106`). + LightCyan, + + /// Color #7 (foreground code `37`, background code `47`). + /// + /// As above, this is not necessarily the foreground color, and may be + /// hard to read on terminals with light backgrounds. + White, + + /// Color #7 (foreground code `97`, background code `107`). + LightGray, + + /// A color number from 0 to 255, for use in 256-color terminal + /// environments. + /// + /// - colors 0 to 7 are the `Black` to `White` variants respectively. + /// These colors can usually be changed in the terminal emulator. + /// - colors 8 to 15 are brighter versions of the eight colors above. + /// These can also usually be changed in the terminal emulator, or it + /// could be configured to use the original colors and show the text in + /// bold instead. It varies depending on the program. + /// - colors 16 to 231 contain several palettes of bright colors, + /// arranged in six squares measuring six by six each. + /// - colors 232 to 255 are shades of grey from black to white. + /// + /// It might make more sense to look at a [color chart][cc]. + /// + /// [cc]: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg + Fixed(u8), + + /// A 24-bit Rgb color, as specified by ISO-8613-3. + Rgb(u8, u8, u8), +} + +impl Default for Color { + fn default() -> Self { + Color::White + } +} + +impl Color { + /// Returns a `Style` with the foreground color set to this color. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Red.normal(); + /// println!("{}", style.paint("hi")); + /// ``` + pub fn normal(self) -> Style { + Style { + foreground: Some(self), + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// bold property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Green.bold(); + /// println!("{}", style.paint("hey")); + /// ``` + pub fn bold(self) -> Style { + Style { + foreground: Some(self), + is_bold: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// dimmed property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Yellow.dimmed(); + /// println!("{}", style.paint("sup")); + /// ``` + pub fn dimmed(self) -> Style { + Style { + foreground: Some(self), + is_dimmed: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// italic property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Blue.italic(); + /// println!("{}", style.paint("greetings")); + /// ``` + pub fn italic(self) -> Style { + Style { + foreground: Some(self), + is_italic: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// underline property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Purple.underline(); + /// println!("{}", style.paint("salutations")); + /// ``` + pub fn underline(self) -> Style { + Style { + foreground: Some(self), + is_underline: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// blink property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Cyan.blink(); + /// println!("{}", style.paint("wazzup")); + /// ``` + pub fn blink(self) -> Style { + Style { + foreground: Some(self), + is_blink: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// reverse property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Black.reverse(); + /// println!("{}", style.paint("aloha")); + /// ``` + pub fn reverse(self) -> Style { + Style { + foreground: Some(self), + is_reverse: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// hidden property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::White.hidden(); + /// println!("{}", style.paint("ahoy")); + /// ``` + pub fn hidden(self) -> Style { + Style { + foreground: Some(self), + is_hidden: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// strikethrough property set. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Fixed(244).strikethrough(); + /// println!("{}", style.paint("yo")); + /// ``` + pub fn strikethrough(self) -> Style { + Style { + foreground: Some(self), + is_strikethrough: true, + ..Style::default() + } + } + + /// Returns a `Style` with the foreground color set to this color and the + /// background color property set to the given color. + /// + /// # Examples + /// + /// ``` + /// use nu_ansi_term::Color; + /// + /// let style = Color::Rgb(31, 31, 31).on(Color::White); + /// println!("{}", style.paint("eyyyy")); + /// ``` + pub fn on(self, background: Color) -> Style { + Style { + foreground: Some(self), + background: Some(background), + ..Style::default() + } + } +} + +impl From for Style { + /// You can turn a `Color` into a `Style` with the foreground color set + /// with the `From` trait. + /// + /// ``` + /// use nu_ansi_term::{Style, Color}; + /// let green_foreground = Style::default().fg(Color::Green); + /// assert_eq!(green_foreground, Color::Green.normal()); + /// assert_eq!(green_foreground, Color::Green.into()); + /// assert_eq!(green_foreground, Style::from(Color::Green)); + /// ``` + fn from(color: Color) -> Style { + color.normal() + } +} + +#[cfg(test)] +#[cfg(feature = "derive_serde_style")] +mod serde_json_tests { + use super::{Color, Style}; + + #[test] + fn color_serialization() { + let colors = &[ + Color::Red, + Color::Blue, + Color::Rgb(123, 123, 123), + Color::Fixed(255), + ]; + + assert_eq!( + serde_json::to_string(&colors).unwrap(), + String::from("[\"Red\",\"Blue\",{\"Rgb\":[123,123,123]},{\"Fixed\":255}]") + ); + } + + #[test] + fn color_deserialization() { + let colors = [ + Color::Red, + Color::Blue, + Color::Rgb(123, 123, 123), + Color::Fixed(255), + ]; + + for color in colors { + let serialized = serde_json::to_string(&color).unwrap(); + let deserialized: Color = serde_json::from_str(&serialized).unwrap(); + + assert_eq!(color, deserialized); + } + } + + #[test] + fn style_serialization() { + let style = Style::default(); + + assert_eq!(serde_json::to_string(&style).unwrap(), "{\"foreground\":null,\"background\":null,\"is_bold\":false,\"is_dimmed\":false,\"is_italic\":false,\"is_underline\":false,\"is_blink\":false,\"is_reverse\":false,\"is_hidden\":false,\"is_strikethrough\":false}".to_string()); + } +} diff --git a/crates/nu-ansi-term/src/util.rs b/crates/nu-ansi-term/src/util.rs new file mode 100644 index 0000000000..d666459588 --- /dev/null +++ b/crates/nu-ansi-term/src/util.rs @@ -0,0 +1,80 @@ +use crate::display::{AnsiString, AnsiStrings}; +use std::ops::Deref; + +/// Return a substring of the given ANSIStrings sequence, while keeping the formatting. +pub fn sub_string<'a>( + start: usize, + len: usize, + strs: &AnsiStrings<'a>, +) -> Vec> { + let mut vec = Vec::new(); + let mut pos = start; + let mut len_rem = len; + + for i in strs.0.iter() { + let fragment = i.deref(); + let frag_len = fragment.len(); + if pos >= frag_len { + pos -= frag_len; + continue; + } + if len_rem == 0 { + break; + } + + let end = pos + len_rem; + let pos_end = if end >= frag_len { frag_len } else { end }; + + vec.push(i.style_ref().paint(String::from(&fragment[pos..pos_end]))); + + if end <= frag_len { + break; + } + + len_rem -= pos_end - pos; + pos = 0; + } + + vec +} + +/// Return a concatenated copy of `strs` without the formatting, as an allocated `String`. +pub fn unstyle(strs: &AnsiStrings) -> String { + let mut s = String::new(); + + for i in strs.0.iter() { + s += i.deref(); + } + + s +} + +/// Return the unstyled length of ANSIStrings. This is equaivalent to `unstyle(strs).len()`. +pub fn unstyled_len(strs: &AnsiStrings) -> usize { + let mut l = 0; + for i in strs.0.iter() { + l += i.deref().len(); + } + l +} + +#[cfg(test)] +mod test { + use super::*; + use crate::Color::*; + + #[test] + fn test() { + let l = [ + Black.paint("first"), + Red.paint("-second"), + White.paint("-third"), + ]; + let a = AnsiStrings(&l); + assert_eq!(unstyle(&a), "first-second-third"); + assert_eq!(unstyled_len(&a), 18); + + let l2 = [Black.paint("st"), Red.paint("-second"), White.paint("-t")]; + assert_eq!(sub_string(3, 11, &a), l2); + } +} diff --git a/crates/nu-ansi-term/src/windows.rs b/crates/nu-ansi-term/src/windows.rs new file mode 100644 index 0000000000..828e355733 --- /dev/null +++ b/crates/nu-ansi-term/src/windows.rs @@ -0,0 +1,62 @@ +/// Enables ANSI code support on Windows 10. +/// +/// This uses Windows API calls to alter the properties of the console that +/// the program is running in. +/// +/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx +/// +/// Returns a `Result` with the Windows error code if unsuccessful. +#[cfg(windows)] +pub fn enable_ansi_support() -> Result<(), u32> { + // ref: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#EXAMPLE_OF_ENABLING_VIRTUAL_TERMINAL_PROCESSING @@ https://archive.is/L7wRJ#76% + + use std::ffi::OsStr; + use std::iter::once; + use std::os::windows::ffi::OsStrExt; + use std::ptr::null_mut; + use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; + use winapi::um::errhandlingapi::GetLastError; + use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING}; + use winapi::um::handleapi::INVALID_HANDLE_VALUE; + use winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE}; + + const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004; + + unsafe { + // ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew + // Using `CreateFileW("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected + let console_out_name: Vec = + OsStr::new("CONOUT$").encode_wide().chain(once(0)).collect(); + let console_handle = CreateFileW( + console_out_name.as_ptr(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + null_mut(), + OPEN_EXISTING, + 0, + null_mut(), + ); + if console_handle == INVALID_HANDLE_VALUE { + return Err(GetLastError()); + } + + // ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode + let mut console_mode: u32 = 0; + if 0 == GetConsoleMode(console_handle, &mut console_mode) { + return Err(GetLastError()); + } + + // VT processing not already enabled? + if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 { + // https://docs.microsoft.com/en-us/windows/console/setconsolemode + if 0 == SetConsoleMode( + console_handle, + console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING, + ) { + return Err(GetLastError()); + } + } + } + + Ok(()) +} diff --git a/crates/nu-ansi-term/src/write.rs b/crates/nu-ansi-term/src/write.rs new file mode 100644 index 0000000000..552771918f --- /dev/null +++ b/crates/nu-ansi-term/src/write.rs @@ -0,0 +1,37 @@ +use std::fmt; +use std::io; + +pub trait AnyWrite { + type Wstr: ?Sized; + type Error; + + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Self::Error>; + + fn write_str(&mut self, s: &Self::Wstr) -> Result<(), Self::Error>; +} + +impl<'a> AnyWrite for dyn fmt::Write + 'a { + type Wstr = str; + type Error = fmt::Error; + + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Self::Error> { + fmt::Write::write_fmt(self, fmt) + } + + fn write_str(&mut self, s: &Self::Wstr) -> Result<(), Self::Error> { + fmt::Write::write_str(self, s) + } +} + +impl<'a> AnyWrite for dyn io::Write + 'a { + type Wstr = [u8]; + type Error = io::Error; + + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Self::Error> { + io::Write::write_fmt(self, fmt) + } + + fn write_str(&mut self, s: &Self::Wstr) -> Result<(), Self::Error> { + io::Write::write_all(self, s) + } +} diff --git a/crates/nu-cli/Cargo.toml b/crates/nu-cli/Cargo.toml index 92ae36ede7..f5b596e0fe 100644 --- a/crates/nu-cli/Cargo.toml +++ b/crates/nu-cli/Cargo.toml @@ -1,59 +1,16 @@ [package] -<<<<<<< HEAD -authors = ["The Nu Project Contributors"] -description = "CLI for nushell" -edition = "2018" -license = "MIT" name = "nu-cli" -version = "0.43.0" -build = "build.rs" - -[lib] -doctest = false - -[dependencies] -nu-completion = { version = "0.43.0", path="../nu-completion" } -nu-command = { version = "0.43.0", path="../nu-command" } -nu-data = { version = "0.43.0", path="../nu-data" } -nu-engine = { version = "0.43.0", path="../nu-engine" } -nu-errors = { version = "0.43.0", path="../nu-errors" } -nu-parser = { version = "0.43.0", path="../nu-parser" } -nu-protocol = { version = "0.43.0", path="../nu-protocol" } -nu-source = { version = "0.43.0", path="../nu-source" } -nu-stream = { version = "0.43.0", path="../nu-stream" } -nu-ansi-term = { version = "0.43.0", path="../nu-ansi-term" } -nu-path = { version = "0.43.0", path="../nu-path" } - -indexmap ="1.6.1" -log = "0.4.14" -pretty_env_logger = "0.4.0" -strip-ansi-escapes = "0.1.0" -rustyline = { version="9.0.0", optional=true } -ctrlc = { version="3.1.7", optional=true } -shadow-rs = { version = "0.8.1", default-features = false, optional = true } -serde = { version="1.0.123", features=["derive"] } -serde_yaml = "0.8.16" -lazy_static = "1.4.0" - -[build-dependencies] -shadow-rs = "0.8.1" - -[features] -default = ["shadow-rs"] -rustyline-support = ["rustyline", "nu-engine/rustyline-support"] -stable = [] -======= -name = "nu-cli" -version = "0.1.0" +version = "0.59.0" edition = "2021" [dependencies] -nu-engine = { path = "../nu-engine" } -nu-path = { path = "../nu-path" } -nu-parser = { path = "../nu-parser" } -nu-protocol = { path = "../nu-protocol" } -# nu-ansi-term = { path = "../nu-ansi-term" } +nu-engine = { path = "../nu-engine", version = "0.59.0" } +nu-path = { path = "../nu-path", version = "0.59.0" } +nu-parser = { path = "../nu-parser", version = "0.59.0" } +nu-protocol = { path = "../nu-protocol", version = "0.59.0" } +# nu-ansi-term = { path = "../nu-ansi-term", version = "0.59.0" } nu-ansi-term = "0.42.0" + nu-color-config = { path = "../nu-color-config" } miette = { version = "3.0.0", features = ["fancy"] } @@ -62,4 +19,3 @@ reedline = { git = "https://github.com/nushell/reedline", branch = "main" } log = "0.4" is_executable = "1.0.1" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-cli/src/lib.rs b/crates/nu-cli/src/lib.rs index 8476225688..c00d104f2c 100644 --- a/crates/nu-cli/src/lib.rs +++ b/crates/nu-cli/src/lib.rs @@ -1,20 +1,3 @@ -<<<<<<< HEAD -pub mod app; -mod cli; -#[cfg(feature = "rustyline-support")] -mod keybinding; -mod line_editor; -#[cfg(feature = "rustyline-support")] -mod shell; - -#[cfg(feature = "rustyline-support")] -pub use crate::cli::cli; - -pub use crate::app::App; -pub use crate::cli::{parse_and_eval, register_plugins, run_script_file}; - -pub use nu_command::create_default_context; -======= mod completions; mod errors; mod nu_highlight; @@ -28,4 +11,3 @@ pub use nu_highlight::NuHighlight; pub use prompt::NushellPrompt; pub use syntax_highlight::NuHighlighter; pub use validation::NuValidator; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-color-config/Cargo.toml b/crates/nu-color-config/Cargo.toml index 8979c0c09a..373a951620 100644 --- a/crates/nu-color-config/Cargo.toml +++ b/crates/nu-color-config/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "nu-color-config" -version = "0.1.0" +version = "0.59.0" edition = "2021" [dependencies] -nu-protocol = { path = "../nu-protocol" } -# nu-ansi-term = { path = "../nu-ansi-term" } +nu-protocol = { path = "../nu-protocol", version = "0.59.0" } +# nu-ansi-term = { path = "../nu-ansi-term", version = "0.59.0" } nu-ansi-term = "0.42.0" -nu-json = { path = "../nu-json" } -nu-table = { path = "../nu-table" } + +nu-json = { path = "../nu-json", version = "0.59.0" } +nu-table = { path = "../nu-table", version = "0.59.0" } serde = { version="1.0.123", features=["derive"] } diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index 3f8888213f..5c6cdbfb0c 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -1,55 +1,6 @@ [package] -<<<<<<< HEAD -authors = ["The Nu Project Contributors"] -build = "build.rs" -description = "Commands for Nushell" -edition = "2018" -license = "MIT" name = "nu-command" -version = "0.43.0" - -[lib] -doctest = false - -[dependencies] -nu-data = { version = "0.43.0", path="../nu-data" } -nu-engine = { version = "0.43.0", path="../nu-engine" } -nu-errors = { version = "0.43.0", path="../nu-errors" } -nu-json = { version = "0.43.0", path="../nu-json" } -nu-path = { version = "0.43.0", path="../nu-path" } -nu-parser = { version = "0.43.0", path="../nu-parser" } -nu-plugin = { version = "0.43.0", path="../nu-plugin" } -nu-protocol = { version = "0.43.0", path="../nu-protocol" } -nu-serde = { version = "0.43.0", path="../nu-serde" } -nu-source = { version = "0.43.0", path="../nu-source" } -nu-stream = { version = "0.43.0", path="../nu-stream" } -nu-table = { version = "0.43.0", path="../nu-table" } -nu-test-support = { version = "0.43.0", path="../nu-test-support" } -nu-value-ext = { version = "0.43.0", path="../nu-value-ext" } -nu-ansi-term = { version = "0.43.0", path="../nu-ansi-term" } -nu-pretty-hex = { version = "0.43.0", path="../nu-pretty-hex" } - -url = "2.2.1" -mime = "0.3.16" -heck = "0.4.0" -base64 = "0.13.0" -bigdecimal = { version = "0.3.0", features = ["serde"] } -calamine = "0.18.0" -chrono = { version="0.4.19", features=["serde"] } -chrono-tz = "0.5.3" -crossterm = { version="0.19.0", optional=true } -csv = "1.1.3" -ctrlc = { version="3.1.7", optional=true } -derive-new = "0.5.8" -dirs-next = "2.0.0" -dtparse = "1.2.0" -eml-parser = "0.1.0" -encoding_rs = "0.8.28" -filesize = "0.2.0" -futures = { version="0.3.12", features=["compat", "io-compat"] } -======= -name = "nu-command" -version = "0.1.0" +version = "0.59.0" edition = "2021" build = "build.rs" @@ -57,18 +8,20 @@ build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +# nu-ansi-term = {path = "../nu-ansi-term", version = "0.59.0" } nu-ansi-term = "0.42.0" -nu-color-config = { path = "../nu-color-config" } -nu-engine = { path = "../nu-engine" } -nu-json = { path = "../nu-json" } -nu-parser = { path = "../nu-parser" } -nu-path = { path = "../nu-path" } -nu-pretty-hex = { path = "../nu-pretty-hex" } -nu-protocol = { path = "../nu-protocol" } -nu-system = { path = "../nu-system" } -nu-table = { path = "../nu-table" } -nu-term-grid = { path = "../nu-term-grid" } -nu-test-support = { path = "../nu-test-support" } + +nu-color-config = { path = "../nu-color-config", version = "0.59.0" } +nu-engine = { path = "../nu-engine", version = "0.59.0" } +nu-json = { path = "../nu-json", version = "0.59.0" } +nu-parser = { path = "../nu-parser", version = "0.59.0" } +nu-path = { path = "../nu-path", version = "0.59.0" } +nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.59.0" } +nu-protocol = { path = "../nu-protocol", version = "0.59.0" } +nu-system = { path = "../nu-system", version = "0.59.0" } +nu-table = { path = "../nu-table", version = "0.59.0" } +nu-term-grid = { path = "../nu-term-grid", version = "0.59.0" } +nu-test-support = { path = "../nu-test-support", version = "0.59.0" } # Potential dependencies for extras base64 = "0.13.0" @@ -85,55 +38,10 @@ dtparse = "1.2.0" eml-parser = "0.1.0" encoding_rs = "0.8.30" filesize = "0.2.0" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce glob = "0.3.0" htmlescape = "0.3.1" ical = "0.7.0" indexmap = { version="1.7", features=["serde-1"] } -<<<<<<< HEAD -itertools = "0.10.0" -lazy_static = "1.*" -log = "0.4.14" -md-5 = "0.9.1" -meval = "0.2.0" -num-bigint = { version="0.4.3", features=["serde"] } -num-format = { version="0.4.0", features=["with-num-bigint"] } -num-traits = "0.2.14" -parking_lot = "0.11.1" -quick-xml = "0.22" -rand = "0.8" -regex = "1.4.3" -reqwest = {version = "0.11", optional = true } -roxmltree = "0.14.0" -rust-embed = "5.9.0" -rustyline = { version="9.0.0", optional=true } -serde = { version="1.0.123", features=["derive"] } -serde_ini = "0.2.0" -serde_json = "1.0.61" -serde_urlencoded = "0.7.0" -serde_yaml = "0.8.16" -sha2 = "0.9.3" -strip-ansi-escapes = "0.1.0" -sysinfo = { version = "0.23.0", optional = true } -thiserror = "1.0.26" -term = { version="0.7.0", optional=true } -term_size = "0.3.2" -titlecase = "1.1.0" -tokio = { version = "1", features = ["rt-multi-thread"], optional = true } -toml = "0.5.8" -trash = { version = "2.0.2", optional = true } -unicode-segmentation = "1.8" -uuid_crate = { package="uuid", version="0.8.2", features=["v4"], optional=true } -which = { version="4.1.0", optional=true } -zip = { version="0.5.9", optional=true } -digest = "0.9.0" - -[dependencies.polars] -version = "0.17.0" -optional = true -default-features = false -features = ["docs", "zip_with", "csv-file", "temporal", "performant", "pretty_fmt", "dtype-slim", "parquet", "json", "random", "pivot", "strings", "is_in", "cum_agg", "rolling_window"] -======= Inflector = "0.11" itertools = "0.10.0" lazy_static = "1.4.0" @@ -170,19 +78,11 @@ uuid = { version = "0.8.2", features = ["v4"] } which = { version = "4.2.2", optional = true } reedline = { git = "https://github.com/nushell/reedline", branch = "main" } zip = { version="0.5.9", optional = true } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [target.'cfg(unix)'.dependencies] umask = "1.0.0" users = "0.11.0" -<<<<<<< HEAD -# TODO this will be possible with new dependency resolver -# (currently on nightly behind -Zfeatures=itarget): -# https://github.com/rust-lang/cargo/issues/7914 -# [target.'cfg(not(windows))'.dependencies] -# num-format = { version = "0.4", features = ["with-system-locale"] } -======= [dependencies.polars] version = "0.18.0" optional = true @@ -196,29 +96,12 @@ features = [ trash-support = ["trash"] plugin = ["nu-parser/plugin"] dataframe = ["polars", "num"] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce [build-dependencies] shadow-rs = "0.8.1" [dev-dependencies] -<<<<<<< HEAD -quickcheck = "1.0.3" -quickcheck_macros = "1.0.0" -hamcrest2 = "0.3.0" - -[features] -rustyline-support = ["rustyline"] -stable = [] -trash-support = ["trash"] -dataframe = ["nu-protocol/dataframe", "polars"] -fetch = ["reqwest", "tokio"] -post = ["reqwest", "tokio"] -sys = ["sysinfo"] -ps = ["sysinfo"] -======= hamcrest2 = "0.3.0" dirs-next = "2.0.0" quickcheck = "1.0.3" quickcheck_macros = "1.0.0" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-command/assets/228_themes.zip b/crates/nu-command/assets/228_themes.zip new file mode 100644 index 0000000000000000000000000000000000000000..eca629d50c5ba9be44baee239a91824bbd56fb8c GIT binary patch literal 22290 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 literal 0 HcmV?d00001 diff --git a/crates/nu-command/build.rs b/crates/nu-command/build.rs new file mode 100644 index 0000000000..4a0dfc4591 --- /dev/null +++ b/crates/nu-command/build.rs @@ -0,0 +1,3 @@ +fn main() -> shadow_rs::SdResult<()> { + shadow_rs::new() +} diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 8de061c1e3..1e53a6bac3 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -1,376 +1,3 @@ -<<<<<<< HEAD -use crate::prelude::*; -use nu_engine::whole_stream_command; -use std::error::Error; - -pub fn create_default_context(interactive: bool) -> Result> { - let context = EvaluationContext::basic(); - - { - use crate::commands::*; - - context.add_commands(vec![ - // Fundamentals - whole_stream_command(NuPlugin), - whole_stream_command(Let), - whole_stream_command(LetEnv), - whole_stream_command(UnletEnv), - whole_stream_command(LoadEnv), - whole_stream_command(Def), - whole_stream_command(Source), - whole_stream_command(Alias), - whole_stream_command(Unalias), - whole_stream_command(Ignore), - whole_stream_command(Tutor), - whole_stream_command(Find), - // System/file operations - whole_stream_command(ErrorMake), - whole_stream_command(Exec), - whole_stream_command(Pwd), - whole_stream_command(Ls), - whole_stream_command(Du), - whole_stream_command(Cd), - whole_stream_command(Remove), - whole_stream_command(Open), - whole_stream_command(Pathvar), - whole_stream_command(PathvarAdd), - whole_stream_command(PathvarRemove), - whole_stream_command(PathvarReset), - whole_stream_command(PathvarAppend), - whole_stream_command(PathvarSave), - whole_stream_command(Config), - whole_stream_command(ConfigGet), - whole_stream_command(ConfigSet), - whole_stream_command(ConfigSetInto), - whole_stream_command(ConfigClear), - whole_stream_command(ConfigRemove), - whole_stream_command(ConfigPath), - whole_stream_command(Help), - whole_stream_command(History), - whole_stream_command(Save), - whole_stream_command(Touch), - whole_stream_command(Cpy), - whole_stream_command(Date), - whole_stream_command(DateListTimeZone), - whole_stream_command(DateNow), - whole_stream_command(DateToTable), - whole_stream_command(DateToTimeZone), - whole_stream_command(DateFormat), - whole_stream_command(DateHumanize), - whole_stream_command(Cal), - whole_stream_command(Mkdir), - whole_stream_command(Mv), - whole_stream_command(Kill), - whole_stream_command(Version), - whole_stream_command(Clear), - whole_stream_command(Describe), - whole_stream_command(Which), - whole_stream_command(Debug), - whole_stream_command(WithEnv), - whole_stream_command(Do), - whole_stream_command(Sleep), - // Statistics - whole_stream_command(Size), - whole_stream_command(Length), - whole_stream_command(Benchmark), - // Metadata - whole_stream_command(Tags), - // Shells - whole_stream_command(Next), - whole_stream_command(Previous), - whole_stream_command(Goto), - whole_stream_command(Shells), - whole_stream_command(Enter), - whole_stream_command(Exit), - // Viz - whole_stream_command(Chart), - // Viewers - whole_stream_command(Autoview), - whole_stream_command(Table), - // Text manipulation - whole_stream_command(Hash), - whole_stream_command(HashBase64), - whole_stream_command(HashMd5::default()), - whole_stream_command(HashSha256::default()), - whole_stream_command(Split), - whole_stream_command(SplitColumn), - whole_stream_command(SplitRow), - whole_stream_command(SplitChars), - whole_stream_command(Lines), - whole_stream_command(Echo), - whole_stream_command(Parse), - whole_stream_command(Str), - whole_stream_command(StrToDecimal), - whole_stream_command(StrToInteger), - whole_stream_command(StrDowncase), - whole_stream_command(StrUpcase), - whole_stream_command(StrCapitalize), - whole_stream_command(StrFindReplace), - whole_stream_command(StrSubstring), - whole_stream_command(StrToDatetime), - whole_stream_command(StrContains), - whole_stream_command(StrIndexOf), - whole_stream_command(StrTrim), - whole_stream_command(StrStartsWith), - whole_stream_command(StrEndsWith), - whole_stream_command(StrCollect), - whole_stream_command(StrLength), - whole_stream_command(StrLPad), - whole_stream_command(StrReverse), - whole_stream_command(StrRPad), - whole_stream_command(StrCamelCase), - whole_stream_command(StrPascalCase), - whole_stream_command(StrKebabCase), - whole_stream_command(StrSnakeCase), - whole_stream_command(StrScreamingSnakeCase), - whole_stream_command(BuildString), - whole_stream_command(Ansi), - whole_stream_command(AnsiStrip), - whole_stream_command(AnsiGradient), - whole_stream_command(Char), - whole_stream_command(DetectColumns), - // Column manipulation - whole_stream_command(DropColumn), - whole_stream_command(MoveColumn), - whole_stream_command(Reject), - whole_stream_command(Select), - whole_stream_command(Get), - whole_stream_command(Update), - whole_stream_command(UpdateCells), - whole_stream_command(Insert), - whole_stream_command(Into), - whole_stream_command(IntoBinary), - whole_stream_command(IntoColumnPath), - whole_stream_command(IntoInt), - whole_stream_command(IntoFilepath), - whole_stream_command(IntoFilesize), - whole_stream_command(IntoString), - whole_stream_command(SplitBy), - // Row manipulation - whole_stream_command(All), - whole_stream_command(Any), - whole_stream_command(Reverse), - whole_stream_command(Append), - whole_stream_command(Prepend), - whole_stream_command(SortBy), - whole_stream_command(GroupBy), - whole_stream_command(GroupByDate), - whole_stream_command(First), - whole_stream_command(Last), - whole_stream_command(Every), - whole_stream_command(Nth), - whole_stream_command(Drop), - whole_stream_command(DropNth), - whole_stream_command(Format), - whole_stream_command(FileSize), - whole_stream_command(Where), - whole_stream_command(If), - whole_stream_command(Compact), - whole_stream_command(Default), - whole_stream_command(Skip), - whole_stream_command(SkipUntil), - whole_stream_command(SkipWhile), - whole_stream_command(Keep), - whole_stream_command(KeepUntil), - whole_stream_command(KeepWhile), - whole_stream_command(Range), - whole_stream_command(Rename), - whole_stream_command(Uniq), - whole_stream_command(Each), - whole_stream_command(EachGroup), - whole_stream_command(EachWindow), - whole_stream_command(Empty), - whole_stream_command(ForIn), - // Table manipulation - whole_stream_command(Flatten), - whole_stream_command(Merge), - whole_stream_command(Shuffle), - whole_stream_command(Wrap), - whole_stream_command(Pivot), - whole_stream_command(Headers), - whole_stream_command(Reduce), - whole_stream_command(Roll), - whole_stream_command(RollColumn), - whole_stream_command(RollUp), - whole_stream_command(Rotate), - whole_stream_command(RotateCounterClockwise), - whole_stream_command(Zip), - whole_stream_command(Collect), - // Data processing - whole_stream_command(Histogram), - whole_stream_command(Autoenv), - whole_stream_command(AutoenvTrust), - whole_stream_command(AutoenvUntrust), - whole_stream_command(Math), - whole_stream_command(MathAbs), - whole_stream_command(MathAverage), - whole_stream_command(MathEval), - whole_stream_command(MathMedian), - whole_stream_command(MathMinimum), - whole_stream_command(MathMode), - whole_stream_command(MathMaximum), - whole_stream_command(MathStddev), - whole_stream_command(MathSummation), - whole_stream_command(MathVariance), - whole_stream_command(MathProduct), - whole_stream_command(MathRound), - whole_stream_command(MathFloor), - whole_stream_command(MathCeil), - whole_stream_command(MathSqrt), - // File format output - whole_stream_command(To), - whole_stream_command(ToCsv), - whole_stream_command(ToHtml), - whole_stream_command(ToJson), - whole_stream_command(ToMarkdown), - whole_stream_command(ToToml), - whole_stream_command(ToTsv), - whole_stream_command(ToUrl), - whole_stream_command(ToYaml), - whole_stream_command(ToXml), - // File format input - whole_stream_command(From), - whole_stream_command(FromCsv), - whole_stream_command(FromEml), - whole_stream_command(FromTsv), - whole_stream_command(FromSsv), - whole_stream_command(FromIni), - whole_stream_command(FromJson), - whole_stream_command(FromOds), - whole_stream_command(FromToml), - whole_stream_command(FromUrl), - whole_stream_command(FromXlsx), - whole_stream_command(FromXml), - whole_stream_command(FromYaml), - whole_stream_command(FromYml), - whole_stream_command(FromIcs), - whole_stream_command(FromVcf), - // "Private" commands (not intended to be accessed directly) - whole_stream_command(RunExternalCommand { interactive }), - // Random value generation - whole_stream_command(Random), - whole_stream_command(RandomBool), - whole_stream_command(RandomDice), - #[cfg(feature = "uuid_crate")] - whole_stream_command(RandomUUID), - whole_stream_command(RandomInteger), - whole_stream_command(RandomDecimal), - whole_stream_command(RandomChars), - // Path - whole_stream_command(PathBasename), - whole_stream_command(PathCommand), - whole_stream_command(PathDirname), - whole_stream_command(PathExists), - whole_stream_command(PathExpand), - whole_stream_command(PathJoin), - whole_stream_command(PathParse), - whole_stream_command(PathRelativeTo), - whole_stream_command(PathSplit), - whole_stream_command(PathType), - // Url - whole_stream_command(UrlCommand), - whole_stream_command(UrlScheme), - whole_stream_command(UrlPath), - whole_stream_command(UrlHost), - whole_stream_command(UrlQuery), - whole_stream_command(Seq), - whole_stream_command(SeqDates), - whole_stream_command(TermSize), - // Network - #[cfg(feature = "fetch")] - whole_stream_command(Fetch), - #[cfg(feature = "post")] - whole_stream_command(Post), - // System - #[cfg(feature = "ps")] - whole_stream_command(Ps), - #[cfg(feature = "sys")] - whole_stream_command(Sys), - ]); - - //Dataframe commands - #[cfg(feature = "dataframe")] - context.add_commands(vec![ - whole_stream_command(DataFrame), - whole_stream_command(DataFrameOpen), - whole_stream_command(DataFrameList), - whole_stream_command(DataFrameGroupBy), - whole_stream_command(DataFrameAggregate), - whole_stream_command(DataFrameShow), - whole_stream_command(DataFrameSample), - whole_stream_command(DataFrameJoin), - whole_stream_command(DataFrameDrop), - whole_stream_command(DataFrameSelect), - whole_stream_command(DataFrameDTypes), - whole_stream_command(DataFrameDummies), - whole_stream_command(DataFrameFirst), - whole_stream_command(DataFrameLast), - whole_stream_command(DataFrameSlice), - whole_stream_command(DataFrameMelt), - whole_stream_command(DataFramePivot), - whole_stream_command(DataFrameWhere), - whole_stream_command(DataFrameToDF), - whole_stream_command(DataFrameToParquet), - whole_stream_command(DataFrameToCsv), - whole_stream_command(DataFrameSort), - whole_stream_command(DataFrameGet), - whole_stream_command(DataFrameDropDuplicates), - whole_stream_command(DataFrameDropNulls), - whole_stream_command(DataFrameColumn), - whole_stream_command(DataFrameWithColumn), - whole_stream_command(DataFrameFilter), - whole_stream_command(DataFrameSeriesRename), - whole_stream_command(DataFrameValueCounts), - whole_stream_command(DataFrameIsNull), - whole_stream_command(DataFrameIsNotNull), - whole_stream_command(DataFrameAllTrue), - whole_stream_command(DataFrameAllFalse), - whole_stream_command(DataFrameArgMax), - whole_stream_command(DataFrameArgMin), - whole_stream_command(DataFrameArgTrue), - whole_stream_command(DataFrameArgUnique), - whole_stream_command(DataFrameArgSort), - whole_stream_command(DataFrameUnique), - whole_stream_command(DataFrameNUnique), - whole_stream_command(DataFrameNNull), - whole_stream_command(DataFrameIsUnique), - whole_stream_command(DataFrameIsDuplicated), - whole_stream_command(DataFrameIsIn), - whole_stream_command(DataFrameShift), - whole_stream_command(DataFrameSet), - whole_stream_command(DataFrameNot), - whole_stream_command(DataFrameTake), - whole_stream_command(DataFrameSetWithIdx), - whole_stream_command(DataFrameShape), - whole_stream_command(DataFrameReplace), - whole_stream_command(DataFrameReplaceAll), - whole_stream_command(DataFrameStringLengths), - whole_stream_command(DataFrameContains), - whole_stream_command(DataFrameToLowercase), - whole_stream_command(DataFrameToUppercase), - whole_stream_command(DataFrameStringSlice), - whole_stream_command(DataFrameConcatenate), - whole_stream_command(DataFrameAppend), - whole_stream_command(DataFrameGetHour), - whole_stream_command(DataFrameGetMinute), - whole_stream_command(DataFrameGetSecond), - whole_stream_command(DataFrameGetDay), - whole_stream_command(DataFrameGetMonth), - whole_stream_command(DataFrameGetYear), - whole_stream_command(DataFrameGetWeek), - whole_stream_command(DataFrameGetWeekDay), - whole_stream_command(DataFrameGetOrdinal), - whole_stream_command(DataFrameGetNanoSecond), - whole_stream_command(DataFrameStrFTime), - whole_stream_command(DataFrameDescribe), - whole_stream_command(DataFrameRolling), - whole_stream_command(DataFrameCumulative), - whole_stream_command(DataFrameRename), - ]); - } - - Ok(context) -======= use nu_protocol::engine::{EngineState, StateWorkingSet}; use std::path::Path; @@ -729,5 +356,4 @@ pub fn create_default_context(cwd: impl AsRef) -> EngineState { let _ = engine_state.merge_delta(delta, None, &cwd); engine_state ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/src/filters/drop/nth.rs b/crates/nu-command/src/filters/drop/nth.rs index edcb8929a2..e46efa6c3c 100644 --- a/crates/nu-command/src/filters/drop/nth.rs +++ b/crates/nu-command/src/filters/drop/nth.rs @@ -1,9 +1,10 @@ +use itertools::Either; use nu_engine::CallExt; -use nu_protocol::ast::Call; +use nu_protocol::ast::{Call, RangeInclusion}; use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::{ - Category, Example, IntoInterruptiblePipelineData, PipelineData, PipelineIterator, ShellError, - Signature, Span, SyntaxShape, Value, + Category, Example, FromValue, IntoInterruptiblePipelineData, PipelineData, PipelineIterator, + Range, ShellError, Signature, Span, Spanned, SyntaxShape, Value, }; #[derive(Clone)] @@ -16,7 +17,13 @@ impl Command for DropNth { fn signature(&self) -> Signature { Signature::build("drop nth") - .rest("rest", SyntaxShape::Int, "the number of the row to drop") + .required( + "row number or row range", + // FIXME: we can make this accept either Int or Range when we can compose SyntaxShapes + SyntaxShape::Any, + "the number of the row to drop or a range to drop consecutive rows", + ) + .rest("rest", SyntaxShape::Any, "the number of the row to drop") .category(Category::Filters) } @@ -58,6 +65,14 @@ impl Command for DropNth { span: Span::test_data(), }), }, + Example { + description: "Drop range rows from second to fourth", + example: "echo [first second third fourth fifth] | drop nth (1..3)", + result: Some(Value::List { + vals: vec![Value::test_string("first"), Value::test_string("fifth")], + span: Span::test_data(), + }), + }, ] } @@ -68,12 +83,34 @@ impl Command for DropNth { call: &Call, input: PipelineData, ) -> Result { - let mut rows: Vec = call.rest(engine_state, stack, 0)?; - rows.sort_unstable(); - let pipeline_iter: PipelineIterator = input.into_iter(); + // let mut rows: Vec = call.rest(engine_state, stack, 0)?; + // rows.sort_unstable(); + // let pipeline_iter: PipelineIterator = input.into_iter(); + + let number_or_range = extract_int_or_range(engine_state, stack, call)?; + let rows = match number_or_range { + Either::Left(row_number) => { + let and_rows: Vec> = call.rest(engine_state, stack, 1)?; + + let mut rows: Vec<_> = and_rows.into_iter().map(|x| x.item as usize).collect(); + rows.push(row_number as usize); + rows.sort_unstable(); + rows + } + Either::Right(row_range) => { + let from = row_range.from.as_integer()? as usize; + let to = row_range.to.as_integer()? as usize; + + if matches!(row_range.inclusion, RangeInclusion::Inclusive) { + (from..=to).collect() + } else { + (from..to).collect() + } + } + }; Ok(DropNthIterator { - input: pipeline_iter, + input: input.into_iter(), rows, current: 0, } @@ -81,6 +118,26 @@ impl Command for DropNth { } } +fn extract_int_or_range( + engine_state: &EngineState, + stack: &mut Stack, + call: &Call, +) -> Result, ShellError> { + let value = call.req::(engine_state, stack, 0)?; + + let int_opt = value.as_integer().map(Either::Left).ok(); + let range_opt: Result = FromValue::from_value(&value); + + let range_opt = range_opt.map(Either::Right).ok(); + + int_opt.or(range_opt).ok_or_else(|| { + ShellError::TypeMismatch( + "int or range".into(), + value.span().unwrap_or_else(|_| Span::new(0, 0)), + ) + }) +} + struct DropNthIterator { input: PipelineIterator, rows: Vec, diff --git a/crates/nu-command/src/lib.rs b/crates/nu-command/src/lib.rs index 129658c789..3caca19722 100644 --- a/crates/nu-command/src/lib.rs +++ b/crates/nu-command/src/lib.rs @@ -1,32 +1,3 @@ -<<<<<<< HEAD -#![recursion_limit = "2048"] - -#[cfg(test)] -#[macro_use] -extern crate indexmap; - -#[macro_use] -mod prelude; -mod classified; -pub mod commands; -mod default_context; -pub mod utils; - -#[cfg(test)] -mod examples; - -pub use crate::default_context::create_default_context; -pub use nu_data::config; -pub use nu_data::dict::TaggedListBuilder; -pub use nu_data::primitive; -pub use nu_data::value; -pub use nu_stream::{ActionStream, InputStream, InterruptibleStream}; -pub use nu_value_ext::ValueExt; -pub use num_traits::cast::ToPrimitive; - -// TODO: Temporary redirect -pub use nu_protocol::{did_you_mean, TaggedDictBuilder}; -======= mod conversions; mod core_commands; mod date; @@ -77,4 +48,3 @@ mod dataframe; #[cfg(feature = "dataframe")] pub use dataframe::*; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-command/tests/commands/all.rs b/crates/nu-command/tests/commands/all.rs index f103c6f2b0..25a263f6a1 100644 --- a/crates/nu-command/tests/commands/all.rs +++ b/crates/nu-command/tests/commands/all.rs @@ -1,24 +1,3 @@ -<<<<<<< HEAD -use nu_test_support::pipeline as input; -use nu_test_support::playground::{says, Playground}; - -use hamcrest2::assert_that; -use hamcrest2::prelude::*; - -#[test] -fn checks_all_rows_are_true() { - Playground::setup("all_test_1", |_, nu| { - assert_that!( - nu.pipeline(&input( - r#" - echo [ "AndrΓ©s", "AndrΓ©s", "AndrΓ©s" ] - | all? $it == "AndrΓ©s" - "# - )), - says().stdout("true") - ); - }) -======= use nu_test_support::{nu, pipeline}; #[test] @@ -32,23 +11,10 @@ fn checks_all_rows_are_true() { )); assert_eq!(actual.out, "true"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] fn checks_all_rows_are_false_with_param() { -<<<<<<< HEAD - Playground::setup("all_test_1", |_, nu| { - assert_that!( - nu.pipeline(&input( - r#" - [1, 2, 3, 4] | all? { |a| $a >= 5 } - "# - )), - says().stdout("false") - ); - }) -======= let actual = nu!( cwd: ".", pipeline( r#" @@ -57,23 +23,10 @@ fn checks_all_rows_are_false_with_param() { )); assert_eq!(actual.out, "false"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] fn checks_all_rows_are_true_with_param() { -<<<<<<< HEAD - Playground::setup("all_test_1", |_, nu| { - assert_that!( - nu.pipeline(&input( - r#" - [1, 2, 3, 4] | all? { |a| $a < 5 } - "# - )), - says().stdout("true") - ); - }) -======= let actual = nu!( cwd: ".", pipeline( r#" @@ -82,21 +35,13 @@ fn checks_all_rows_are_true_with_param() { )); assert_eq!(actual.out, "true"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] fn checks_all_columns_of_a_table_is_true() { -<<<<<<< HEAD - Playground::setup("any_test_1", |_, nu| { - assert_that!( - nu.pipeline(&input( - r#" -======= let actual = nu!( cwd: ".", pipeline( r#" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce echo [ [ first_name, last_name, rusty_at, likes ]; [ AndrΓ©s, Robalino, 10/11/2013, 1 ] @@ -105,16 +50,8 @@ fn checks_all_columns_of_a_table_is_true() { [ Yehuda, Katz, 10/11/2013, 1 ] ] | all? likes > 0 -<<<<<<< HEAD - "# - )), - says().stdout("true") - ); - }) -======= "# )); assert_eq!(actual.out, "true"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/commands/any.rs b/crates/nu-command/tests/commands/any.rs index af41afb49e..817c6605ab 100644 --- a/crates/nu-command/tests/commands/any.rs +++ b/crates/nu-command/tests/commands/any.rs @@ -1,24 +1,3 @@ -<<<<<<< HEAD -use nu_test_support::pipeline as input; -use nu_test_support::playground::{says, Playground}; - -use hamcrest2::assert_that; -use hamcrest2::prelude::*; - -#[test] -fn checks_any_row_is_true() { - Playground::setup("any_test_1", |_, nu| { - assert_that!( - nu.pipeline(&input( - r#" - echo [ "Ecuador", "USA", "New Zealand" ] - | any? $it == "New Zealand" - "# - )), - says().stdout("true") - ); - }) -======= use nu_test_support::{nu, pipeline}; #[test] @@ -32,21 +11,13 @@ fn checks_any_row_is_true() { )); assert_eq!(actual.out, "true"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] fn checks_any_column_of_a_table_is_true() { -<<<<<<< HEAD - Playground::setup("any_test_1", |_, nu| { - assert_that!( - nu.pipeline(&input( - r#" -======= let actual = nu!( cwd: ".", pipeline( r#" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce echo [ [ first_name, last_name, rusty_at, likes ]; [ AndrΓ©s, Robalino, 10/11/2013, 1 ] @@ -55,16 +26,8 @@ fn checks_any_column_of_a_table_is_true() { [ Yehuda, Katz, 10/11/2013, 1 ] ] | any? rusty_at == 10/12/2013 -<<<<<<< HEAD - "# - )), - says().stdout("true") - ); - }) -======= "# )); assert_eq!(actual.out, "true"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/commands/append.rs b/crates/nu-command/tests/commands/append.rs index a41529923e..9652348e51 100644 --- a/crates/nu-command/tests/commands/append.rs +++ b/crates/nu-command/tests/commands/append.rs @@ -1,25 +1,3 @@ -<<<<<<< HEAD -use nu_test_support::pipeline as input; -use nu_test_support::playground::{says, Playground}; - -use hamcrest2::assert_that; -use hamcrest2::prelude::*; - -#[test] -fn adds_a_row_to_the_end() { - Playground::setup("append_test_1", |_, nu| { - assert_that!( - nu.pipeline(&input( - r#" - echo [ "AndrΓ©s N. Robalino", "Jonathan Turner", "Yehuda Katz" ] - | append "pollo loco" - | nth 3 - "# - )), - says().stdout("pollo loco") - ); - }) -======= use nu_test_support::{nu, pipeline}; #[test] @@ -34,5 +12,4 @@ fn adds_a_row_to_the_end() { )); assert_eq!(actual.out, "pollo loco"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/commands/cal.rs b/crates/nu-command/tests/commands/cal.rs index 60028c00bb..70261fd4c7 100644 --- a/crates/nu-command/tests/commands/cal.rs +++ b/crates/nu-command/tests/commands/cal.rs @@ -5,19 +5,11 @@ fn cal_full_year() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - cal -y --full-year 2010 | first | to json - "# - )); - - let first_week_2010_json = r#"{"year":2010,"sunday":null,"monday":null,"tuesday":null,"wednesday":null,"thursday":null,"friday":1,"saturday":2}"#; -======= cal -y --full-year 2010 | first | to json -r "# )); let first_week_2010_json = r#"{"year": 2010,"sunday": null,"monday": null,"tuesday": null,"wednesday": null,"thursday": null,"friday": 1,"saturday": 2}"#; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.out, first_week_2010_json); } @@ -27,19 +19,11 @@ fn cal_february_2020_leap_year() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - cal -ym --full-year 2020 --month-names | where month == "february" | to json - "# - )); - - let cal_february_json = r#"[{"year":2020,"month":"february","sunday":null,"monday":null,"tuesday":null,"wednesday":null,"thursday":null,"friday":null,"saturday":1},{"year":2020,"month":"february","sunday":2,"monday":3,"tuesday":4,"wednesday":5,"thursday":6,"friday":7,"saturday":8},{"year":2020,"month":"february","sunday":9,"monday":10,"tuesday":11,"wednesday":12,"thursday":13,"friday":14,"saturday":15},{"year":2020,"month":"february","sunday":16,"monday":17,"tuesday":18,"wednesday":19,"thursday":20,"friday":21,"saturday":22},{"year":2020,"month":"february","sunday":23,"monday":24,"tuesday":25,"wednesday":26,"thursday":27,"friday":28,"saturday":29}]"#; -======= cal -ym --full-year 2020 --month-names | where month == "february" | to json -r "# )); let cal_february_json = r#"[{"year": 2020,"month": "february","sunday": null,"monday": null,"tuesday": null,"wednesday": null,"thursday": null,"friday": null,"saturday": 1},{"year": 2020,"month": "february","sunday": 2,"monday": 3,"tuesday": 4,"wednesday": 5,"thursday": 6,"friday": 7,"saturday": 8},{"year": 2020,"month": "february","sunday": 9,"monday": 10,"tuesday": 11,"wednesday": 12,"thursday": 13,"friday": 14,"saturday": 15},{"year": 2020,"month": "february","sunday": 16,"monday": 17,"tuesday": 18,"wednesday": 19,"thursday": 20,"friday": 21,"saturday": 22},{"year": 2020,"month": "february","sunday": 23,"monday": 24,"tuesday": 25,"wednesday": 26,"thursday": 27,"friday": 28,"saturday": 29}]"#; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.out, cal_february_json); } @@ -73,19 +57,11 @@ fn cal_week_day_start_monday() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - cal --full-year 2020 -m --month-names --week-start monday | where month == january | to json - "# - )); - - let cal_january_json = r#"[{"month":"january","monday":null,"tuesday":null,"wednesday":1,"thursday":2,"friday":3,"saturday":4,"sunday":5},{"month":"january","monday":6,"tuesday":7,"wednesday":8,"thursday":9,"friday":10,"saturday":11,"sunday":12},{"month":"january","monday":13,"tuesday":14,"wednesday":15,"thursday":16,"friday":17,"saturday":18,"sunday":19},{"month":"january","monday":20,"tuesday":21,"wednesday":22,"thursday":23,"friday":24,"saturday":25,"sunday":26},{"month":"january","monday":27,"tuesday":28,"wednesday":29,"thursday":30,"friday":31,"saturday":null,"sunday":null}]"#; -======= cal --full-year 2020 -m --month-names --week-start monday | where month == january | to json -r "# )); let cal_january_json = r#"[{"month": "january","monday": null,"tuesday": null,"wednesday": 1,"thursday": 2,"friday": 3,"saturday": 4,"sunday": 5},{"month": "january","monday": 6,"tuesday": 7,"wednesday": 8,"thursday": 9,"friday": 10,"saturday": 11,"sunday": 12},{"month": "january","monday": 13,"tuesday": 14,"wednesday": 15,"thursday": 16,"friday": 17,"saturday": 18,"sunday": 19},{"month": "january","monday": 20,"tuesday": 21,"wednesday": 22,"thursday": 23,"friday": 24,"saturday": 25,"sunday": 26},{"month": "january","monday": 27,"tuesday": 28,"wednesday": 29,"thursday": 30,"friday": 31,"saturday": null,"sunday": null}]"#; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.out, cal_january_json); } @@ -95,17 +71,9 @@ fn cal_sees_pipeline_year() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - cal --full-year 1020 | get monday | first 3 | to json - "# - )); - - assert_eq!(actual.out, "[3,10,17]"); -======= cal --full-year 1020 | get monday | first 4 | to json -r "# )); assert_eq!(actual.out, "[null,3,10,17]"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/commands/cd.rs b/crates/nu-command/tests/commands/cd.rs index 8dfe466938..58b468e325 100644 --- a/crates/nu-command/tests/commands/cd.rs +++ b/crates/nu-command/tests/commands/cd.rs @@ -1,17 +1,10 @@ -<<<<<<< HEAD -use nu_test_support::fs::{Stub::EmptyFile, Stub::FileWithContent}; -======= use nu_test_support::fs::Stub::EmptyFile; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use nu_test_support::nu; use nu_test_support::playground::Playground; use std::path::PathBuf; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_change_from_current_directory_using_relative_path() { Playground::setup("cd_test_1", |dirs, _| { @@ -27,11 +20,8 @@ fn filesystem_change_from_current_directory_using_relative_path() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_change_from_current_directory_using_absolute_path() { Playground::setup("cd_test_2", |dirs, _| { @@ -48,11 +38,8 @@ fn filesystem_change_from_current_directory_using_absolute_path() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_switch_back_to_previous_working_directory() { Playground::setup("cd_test_3", |dirs, sandbox| { @@ -72,11 +59,8 @@ fn filesystem_switch_back_to_previous_working_directory() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesytem_change_from_current_directory_using_relative_path_and_dash() { Playground::setup("cd_test_4", |dirs, sandbox| { @@ -97,11 +81,8 @@ fn filesytem_change_from_current_directory_using_relative_path_and_dash() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_change_current_directory_to_parent_directory() { Playground::setup("cd_test_5", |dirs, _| { @@ -117,11 +98,8 @@ fn filesystem_change_current_directory_to_parent_directory() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_change_current_directory_to_two_parents_up_using_multiple_dots() { Playground::setup("cd_test_6", |dirs, sandbox| { @@ -139,11 +117,8 @@ fn filesystem_change_current_directory_to_two_parents_up_using_multiple_dots() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_change_current_directory_to_parent_directory_after_delete_cwd() { Playground::setup("cd_test_7", |dirs, sandbox| { @@ -166,11 +141,8 @@ fn filesystem_change_current_directory_to_parent_directory_after_delete_cwd() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_change_to_home_directory() { Playground::setup("cd_test_8", |dirs, _| { @@ -186,11 +158,8 @@ fn filesystem_change_to_home_directory() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_change_to_a_directory_containing_spaces() { Playground::setup("cd_test_9", |dirs, sandbox| { @@ -211,11 +180,8 @@ fn filesystem_change_to_a_directory_containing_spaces() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_not_a_directory() { Playground::setup("cd_test_10", |dirs, sandbox| { @@ -239,11 +205,8 @@ fn filesystem_not_a_directory() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_directory_not_found() { Playground::setup("cd_test_11", |dirs, _| { @@ -266,11 +229,8 @@ fn filesystem_directory_not_found() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn filesystem_change_directory_to_symlink_relative() { Playground::setup("cd_test_12", |dirs, sandbox| { @@ -290,218 +250,8 @@ fn filesystem_change_directory_to_symlink_relative() { }) } -<<<<<<< HEAD -#[test] -fn valuesystem_change_from_current_path_using_relative_path() { - Playground::setup("cd_test_13", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContent( - "sample.toml", - r#" - [[bin]] - path = "src/plugins/turner.rs" - - [[bin]] - path = "src/plugins/robalino.rs" - - [[bin]] - path = "src/plugins/katz.rs" - "#, - )]); - - let actual = nu!( - cwd: dirs.test(), - r#" - enter sample.toml - cd bin - pwd - exit - "# - ); - - assert_eq!(PathBuf::from(actual.out), PathBuf::from("/bin")); - }) -} - -#[test] -fn valuesystem_change_from_current_path_using_absolute_path() { - Playground::setup("cd_test_14", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContent( - "sample.toml", - r#" - [dependencies] - turner-ts = "0.1.1" - robalino-tkd = "0.0.1" - katz-ember = "0.2.3" - - [[bin]] - path = "src/plugins/arepa.rs" - - [[bin]] - path = "src/plugins/bbq.rs" - "#, - )]); - - let actual = nu!( - cwd: dirs.test(), - r#" - enter sample.toml - cd bin - cd /dependencies - pwd - exit - "# - ); - - assert_eq!(PathBuf::from(actual.out), PathBuf::from("/dependencies")); - }) -} - -#[test] -fn valuesystem_switch_back_to_previous_working_path() { - Playground::setup("cd_test_15", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContent( - "sample.toml", - r#" - [dependencies] - turner-ts = "0.1.1" - robalino-tkd = "0.0.1" - katz-ember = "0.2.3" - odin-gf = "0.2.1" - - [[bin]] - path = "src/plugins/arepa.rs" - - [[bin]] - path = "src/plugins/bbq.rs" - "#, - )]); - - let actual = nu!( - cwd: dirs.test(), - r#" - enter sample.toml - cd dependencies - cd /bin - cd - - pwd - exit - "# - ); - - assert_eq!(PathBuf::from(actual.out), PathBuf::from("/dependencies")); - }) -} - -#[test] -fn valuesystem_change_from_current_path_using_relative_path_and_dash() { - Playground::setup("cd_test_16", |dirs, sandbox| { - sandbox - .with_files(vec![FileWithContent( - "sample.toml", - r#" - [package] - - = ["Yehuda Katz ", "Jonathan Turner ", "AndrΓ©s N. Robalino "] - - [[bin]] - path = "src/plugins/arepa.rs" - - [[bin]] - path = "src/plugins/bbq.rs" - "# - )]); - - let actual = nu!( - cwd: dirs.test(), - r#" - enter sample.toml - cd package/- - cd /bin - cd - - pwd - exit - "# - ); - - assert_eq!(PathBuf::from(actual.out), PathBuf::from("/package/-")); - }) -} - -#[test] -fn valuesystem_change_current_path_to_parent_path() { - Playground::setup("cd_test_17", |dirs, sandbox| { - sandbox - .with_files(vec![FileWithContent( - "sample.toml", - r#" - [package] - emberenios = ["Yehuda Katz ", "Jonathan Turner ", "AndrΓ©s N. Robalino "] - "# - )]); - - let actual = nu!( - cwd: dirs.test(), - r#" - enter sample.toml - cd package/emberenios - cd .. - pwd - exit - "# - ); - - assert_eq!(PathBuf::from(actual.out), PathBuf::from("/package")); - }) -} - -#[test] -fn valuesystem_change_to_a_path_containing_spaces() { - Playground::setup("cd_test_18", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContent( - "sample.toml", - r#" - ["pa que te"] - el = "pollo loco" - "#, - )]); - - let actual = nu!( - cwd: dirs.test(), - r#" - enter sample.toml - cd "pa que te" - pwd - exit - "# - ); - - assert_eq!( - PathBuf::from(actual.out), - PathBuf::from("/").join("pa que te") - ); - }) -} - -#[test] -fn valuesystem_path_not_found() { - Playground::setup("cd_test_19", |dirs, _| { - let actual = nu!( - cwd: dirs.formats(), - r#" - enter cargo_sample.toml - cd im_a_path_that_does_not_exist - exit - "# - ); - - assert!(actual.err.contains("Can not change to path inside")); - assert!(actual.err.contains("No such path exists")); - }) -} - -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[cfg(target_os = "windows")] #[test] fn test_change_windows_drive() { diff --git a/crates/nu-command/tests/commands/compact.rs b/crates/nu-command/tests/commands/compact.rs new file mode 100644 index 0000000000..21b4db674d --- /dev/null +++ b/crates/nu-command/tests/commands/compact.rs @@ -0,0 +1,50 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn discards_rows_where_given_column_is_empty() { + Playground::setup("compact_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "los_tres_amigos.json", + r#" + { + "amigos": [ + {"name": "Yehuda", "rusty_luck": 1}, + {"name": "Jonathan", "rusty_luck": 1}, + {"name": "Andres", "rusty_luck": 1}, + {"name":"GorbyPuff"} + ] + } + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open los_tres_amigos.json + | get amigos + | compact rusty_luck + | length + "# + )); + + assert_eq!(actual.out, "3"); + }); +} +#[test] +fn discards_empty_rows_by_default() { + Playground::setup("compact_test_2", |dirs, _| { + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + echo "[1,2,3,14,null]" + | from json + | compact + | length + "# + )); + + assert_eq!(actual.out, "4"); + }); +} diff --git a/crates/nu-command/tests/commands/cp.rs b/crates/nu-command/tests/commands/cp.rs index 233c283962..76da707531 100644 --- a/crates/nu-command/tests/commands/cp.rs +++ b/crates/nu-command/tests/commands/cp.rs @@ -31,11 +31,8 @@ fn copies_the_file_inside_directory_if_path_to_copy_is_directory() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn error_if_attempting_to_copy_a_directory_to_another_directory() { Playground::setup("cp_test_3", |dirs, _| { @@ -80,11 +77,8 @@ fn copies_the_directory_inside_directory_if_path_to_copy_is_directory_and_with_r }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn deep_copies_with_recursive_flag() { Playground::setup("cp_test_5", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/def.rs b/crates/nu-command/tests/commands/def.rs index ff02eb72b3..899b25a20c 100644 --- a/crates/nu-command/tests/commands/def.rs +++ b/crates/nu-command/tests/commands/def.rs @@ -1,12 +1,9 @@ use nu_test_support::nu; use nu_test_support::playground::Playground; use std::fs; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn def_with_comment() { Playground::setup("def_with_comment", |dirs, _| { diff --git a/crates/nu-command/tests/commands/default.rs b/crates/nu-command/tests/commands/default.rs new file mode 100644 index 0000000000..334b45ee68 --- /dev/null +++ b/crates/nu-command/tests/commands/default.rs @@ -0,0 +1,35 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn adds_row_data_if_column_missing() { + Playground::setup("default_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "los_tres_amigos.json", + r#" + { + "amigos": [ + {"name": "Yehuda"}, + {"name": "Jonathan", "rusty_luck": 0}, + {"name": "Andres", "rusty_luck": 0}, + {"name":"GorbyPuff"} + ] + } + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open los_tres_amigos.json + | get amigos + | default rusty_luck 1 + | where rusty_luck == 1 + | length + "# + )); + + assert_eq!(actual.out, "2"); + }); +} diff --git a/crates/nu-command/tests/commands/drop.rs b/crates/nu-command/tests/commands/drop.rs index 7c303565ac..76e908ce82 100644 --- a/crates/nu-command/tests/commands/drop.rs +++ b/crates/nu-command/tests/commands/drop.rs @@ -1,10 +1,7 @@ use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn columns() { let actual = nu!( @@ -25,11 +22,8 @@ fn columns() { assert_eq!(actual.out, "1"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn more_columns_than_table_has() { let actual = nu!( @@ -76,18 +70,17 @@ fn more_rows_than_table_has() { assert_eq!(actual.out, "0"); } -<<<<<<< HEAD #[test] fn nth_range_inclusive() { - let actual = nu!(cwd: ".", "echo 10..15 | drop nth (2..3) | to json"); + let actual = nu!(cwd: ".", "echo 10..15 | drop nth (2..3) | to json --raw"); assert_eq!(actual.out, "[10,11,14,15]"); } #[test] fn nth_range_exclusive() { - let actual = nu!(cwd: ".", "echo 10..15 | drop nth (1..<3) | to json"); + let actual = nu!(cwd: ".", "echo 10..15 | drop nth (1..<3) | to json --raw"); assert_eq!(actual.out, "[10,13,14,15]"); } @@ -96,8 +89,5 @@ fn nth_range_exclusive() { fn nth_missing_first_argument() { let actual = nu!(cwd: ".", "echo 10..15 | drop nth \"\""); - assert!(actual.err.contains("Expected int or range")); - assert!(actual.err.contains("found string")); + assert!(actual.err.contains("int or range")); } -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-command/tests/commands/each.rs b/crates/nu-command/tests/commands/each.rs index f1da3cb357..eda8b7066a 100644 --- a/crates/nu-command/tests/commands/each.rs +++ b/crates/nu-command/tests/commands/each.rs @@ -5,11 +5,7 @@ fn each_works_separately() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo [1 2 3] | each { echo $it 10 | math sum } | to json -======= echo [1 2 3] | each { echo $it 10 | math sum } | to json -r ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -21,11 +17,7 @@ fn each_group_works() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo [1 2 3 4 5 6] | each group 3 { $it } | to json -======= echo [1 2 3 4 5 6] | each group 3 { $it } | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -37,11 +29,7 @@ fn each_window() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo [1 2 3 4] | each window 3 { $it } | to json -======= echo [1 2 3 4] | each window 3 { $it } | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -53,11 +41,7 @@ fn each_window_stride() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo [1 2 3 4 5 6] | each window 3 -s 2 { echo $it } | to json -======= echo [1 2 3 4 5 6] | each window 3 -s 2 { echo $it } | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -69,19 +53,11 @@ fn each_no_args_in_block() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo [[foo bar]; [a b] [c d] [e f]] | each { to json } | nth 1 | str collect - "# - )); - - assert_eq!(actual.out, r#"{"foo":"c","bar":"d"}"#); -======= echo [[foo bar]; [a b] [c d] [e f]] | each {|i| $i | to json -r } | nth 1 "# )); assert_eq!(actual.out, r#"{"foo": "c","bar": "d"}"#); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] diff --git a/crates/nu-command/tests/commands/echo.rs b/crates/nu-command/tests/commands/echo.rs index 305f4154b8..4da8e2dbec 100644 --- a/crates/nu-command/tests/commands/echo.rs +++ b/crates/nu-command/tests/commands/echo.rs @@ -5,11 +5,7 @@ fn echo_range_is_lazy() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo 1..10000000000 | first 3 | to json -======= echo 1..10000000000 | first 3 | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -21,11 +17,7 @@ fn echo_range_handles_inclusive() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo 1..3 | to json -======= echo 1..3 | each { $it } | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -37,11 +29,7 @@ fn echo_range_handles_exclusive() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo 1..<3 | to json -======= echo 1..<3 | each { $it } | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -53,11 +41,7 @@ fn echo_range_handles_inclusive_down() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo 3..1 | to json -======= echo 3..1 | each { $it } | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -69,11 +53,7 @@ fn echo_range_handles_exclusive_down() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo 3..<1 | to json -======= echo 3..<1 | each { $it } | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); diff --git a/crates/nu-command/tests/commands/empty.rs b/crates/nu-command/tests/commands/empty.rs index 9eff812556..22105ea282 100644 --- a/crates/nu-command/tests/commands/empty.rs +++ b/crates/nu-command/tests/commands/empty.rs @@ -1,10 +1,7 @@ use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn reports_emptiness() { let actual = nu!( @@ -25,11 +22,8 @@ fn reports_emptiness() { assert_eq!(actual.out, "3"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn sets_block_run_value_for_an_empty_column() { let actual = nu!( @@ -51,11 +45,8 @@ fn sets_block_run_value_for_an_empty_column() { assert_eq!(actual.out, "4"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn sets_block_run_value_for_many_empty_columns() { let actual = nu!( @@ -76,11 +67,8 @@ fn sets_block_run_value_for_many_empty_columns() { assert_eq!(actual.out, "6"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn passing_a_block_will_set_contents_on_empty_cells_and_leave_non_empty_ones_untouched() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/enter.rs b/crates/nu-command/tests/commands/enter.rs index b7d46a5ba9..945a740c8a 100644 --- a/crates/nu-command/tests/commands/enter.rs +++ b/crates/nu-command/tests/commands/enter.rs @@ -71,18 +71,3 @@ fn knows_the_filesystems_entered() { )); }) } -<<<<<<< HEAD - -#[test] -fn errors_if_file_not_found() { - Playground::setup("enter_test_2", |dirs, _| { - let actual = nu!( - cwd: dirs.test(), - "enter i_dont_exist.csv" - ); - - assert!(actual.err.contains("Cannot find file")); - }) -} -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-command/tests/commands/every.rs b/crates/nu-command/tests/commands/every.rs index 9aeaff95e5..7fe925065c 100644 --- a/crates/nu-command/tests/commands/every.rs +++ b/crates/nu-command/tests/commands/every.rs @@ -18,11 +18,7 @@ fn gets_all_rows_by_every_zero() { ls | get name | every 0 -<<<<<<< HEAD - | to json -======= | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -49,19 +45,11 @@ fn gets_no_rows_by_every_skip_zero() { ls | get name | every 0 --skip -<<<<<<< HEAD - | to json - "# - )); - - assert_eq!(actual.out, ""); -======= | to json --raw "# )); assert_eq!(actual.out, "[]"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }) } @@ -81,11 +69,7 @@ fn gets_all_rows_by_every_one() { ls | get name | every 1 -<<<<<<< HEAD - | to json -======= | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -96,11 +80,8 @@ fn gets_all_rows_by_every_one() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn gets_no_rows_by_every_skip_one() { Playground::setup("every_test_4", |dirs, sandbox| { @@ -117,11 +98,7 @@ fn gets_no_rows_by_every_skip_one() { ls | get name | every 1 --skip -<<<<<<< HEAD - | to json -======= | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -175,11 +152,7 @@ fn gets_all_rows_except_first_by_every_skip_too_much() { ls | get name | every 999 --skip -<<<<<<< HEAD - | to json -======= | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -204,11 +177,7 @@ fn gets_every_third_row() { ls | get name | every 3 -<<<<<<< HEAD - | to json -======= | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -233,11 +202,7 @@ fn skips_every_third_row() { ls | get name | every 3 --skip -<<<<<<< HEAD - | to json -======= | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); diff --git a/crates/nu-command/tests/commands/find.rs b/crates/nu-command/tests/commands/find.rs index 7a3220d6ac..2dcfb7d925 100644 --- a/crates/nu-command/tests/commands/find.rs +++ b/crates/nu-command/tests/commands/find.rs @@ -19,11 +19,7 @@ fn find_with_list_search_with_char() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - [moe larry curly] | find l | to json -======= [moe larry curly] | find l | to json -r ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -82,19 +78,11 @@ fn find_with_filepath_search_with_string() { ls | get name | find arep -<<<<<<< HEAD - | to json - "# - )); - - assert_eq!(actual.out, r#""arepas.clu""#); -======= | to json -r "# )); assert_eq!(actual.out, r#"["arepas.clu"]"#); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }) } @@ -114,11 +102,7 @@ fn find_with_filepath_search_with_multiple_patterns() { ls | get name | find arep ami -<<<<<<< HEAD - | to json -======= | to json -r ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); diff --git a/crates/nu-command/tests/commands/first.rs b/crates/nu-command/tests/commands/first.rs new file mode 100644 index 0000000000..686fc6565e --- /dev/null +++ b/crates/nu-command/tests/commands/first.rs @@ -0,0 +1,67 @@ +use nu_test_support::fs::Stub::EmptyFile; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn gets_first_rows_by_amount() { + Playground::setup("first_test_1", |dirs, sandbox| { + sandbox.with_files(vec![ + EmptyFile("los.txt"), + EmptyFile("tres.txt"), + EmptyFile("amigos.txt"), + EmptyFile("arepas.clu"), + ]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls + | first 3 + | length + "# + )); + + assert_eq!(actual.out, "3"); + }) +} + +#[test] +fn gets_all_rows_if_amount_higher_than_all_rows() { + Playground::setup("first_test_2", |dirs, sandbox| { + sandbox.with_files(vec![ + EmptyFile("los.txt"), + EmptyFile("tres.txt"), + EmptyFile("amigos.txt"), + EmptyFile("arepas.clu"), + ]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls + | first 99 + | length + "# + )); + + assert_eq!(actual.out, "4"); + }) +} + +#[test] +fn gets_first_row_when_no_amount_given() { + Playground::setup("first_test_3", |dirs, sandbox| { + sandbox.with_files(vec![EmptyFile("caballeros.txt"), EmptyFile("arepas.clu")]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls + | first + | length + "# + )); + + assert_eq!(actual.out, "1"); + }) +} diff --git a/crates/nu-command/tests/commands/flatten.rs b/crates/nu-command/tests/commands/flatten.rs index a3153f0484..3291bb34ef 100644 --- a/crates/nu-command/tests/commands/flatten.rs +++ b/crates/nu-command/tests/commands/flatten.rs @@ -2,11 +2,8 @@ use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; use nu_test_support::playground::Playground; use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn flatten_nested_tables_with_columns() { let actual = nu!( @@ -23,11 +20,8 @@ fn flatten_nested_tables_with_columns() { assert_eq!(actual.out, "Andres,nuno"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn flatten_nested_tables_that_have_many_columns() { let actual = nu!( @@ -88,11 +82,8 @@ fn flatten_row_column_explicitly() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn flatten_row_columns_having_same_column_names_flats_separately() { Playground::setup("flatten_test_2", |dirs, sandbox| { @@ -127,11 +118,8 @@ fn flatten_row_columns_having_same_column_names_flats_separately() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn flatten_table_columns_explicitly() { Playground::setup("flatten_test_3", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/format.rs b/crates/nu-command/tests/commands/format.rs index 254c0c328d..58766393e0 100644 --- a/crates/nu-command/tests/commands/format.rs +++ b/crates/nu-command/tests/commands/format.rs @@ -16,11 +16,8 @@ fn creates_the_resulting_string_from_the_given_fields() { assert_eq!(actual.out, "nu has license ISC"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn given_fields_can_be_column_paths() { let actual = nu!( @@ -34,11 +31,8 @@ fn given_fields_can_be_column_paths() { assert_eq!(actual.out, "nu is a new type of shell"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn can_use_variables() { let actual = nu!( @@ -52,11 +46,8 @@ fn can_use_variables() { assert_eq!(actual.out, "nu is a new type of shell"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn format_filesize_works() { Playground::setup("format_filesize_test_1", |dirs, sandbox| { @@ -80,11 +71,8 @@ fn format_filesize_works() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn format_filesize_works_with_nonempty_files() { Playground::setup( diff --git a/crates/nu-command/tests/commands/get.rs b/crates/nu-command/tests/commands/get.rs index c9faef2a8d..01d98321d7 100644 --- a/crates/nu-command/tests/commands/get.rs +++ b/crates/nu-command/tests/commands/get.rs @@ -130,11 +130,8 @@ fn fetches_more_than_one_column_path() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_fetching_by_column_not_present() { Playground::setup("get_test_6", |dirs, sandbox| { @@ -165,11 +162,8 @@ fn errors_fetching_by_column_not_present() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_fetching_by_column_using_a_number() { Playground::setup("get_test_7", |dirs, sandbox| { @@ -196,12 +190,9 @@ fn errors_fetching_by_column_using_a_number() { .contains("Appears to contain columns. Columns available: 0"),) }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_fetching_by_index_out_of_bounds() { Playground::setup("get_test_8", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/group_by.rs b/crates/nu-command/tests/commands/group_by.rs index 8d21bf2d1c..05f8fe9902 100644 --- a/crates/nu-command/tests/commands/group_by.rs +++ b/crates/nu-command/tests/commands/group_by.rs @@ -71,11 +71,8 @@ fn errors_if_given_unknown_column_name() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_block_given_evaluates_more_than_one_row() { Playground::setup("group_by_test_3", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/hash_/mod.rs b/crates/nu-command/tests/commands/hash_/mod.rs index 93344d7080..bd8a53bcfd 100644 --- a/crates/nu-command/tests/commands/hash_/mod.rs +++ b/crates/nu-command/tests/commands/hash_/mod.rs @@ -26,11 +26,8 @@ fn base64_encode_characterset_binhex() { assert_eq!(actual.out, "F@0NEPjJD97kE\'&bEhFZEP3"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn error_when_invalid_character_set_given() { let actual = nu!( @@ -46,11 +43,8 @@ fn error_when_invalid_character_set_given() { .contains("this is invalid is not a valid character-set")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn base64_decode_characterset_binhex() { let actual = nu!( @@ -94,11 +88,8 @@ fn error_use_both_flags() { .contains("only one of --decode and --encode flags can be used")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn md5_works_with_file() { let actual = nu!( @@ -112,11 +103,8 @@ fn md5_works_with_file() { assert_eq!(actual.out, "4de97601d232c427977ef11db396c951"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn sha256_works_with_file() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/headers.rs b/crates/nu-command/tests/commands/headers.rs index 7b8914fc69..b90bcad1ee 100644 --- a/crates/nu-command/tests/commands/headers.rs +++ b/crates/nu-command/tests/commands/headers.rs @@ -1,10 +1,7 @@ use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn headers_uses_first_row_as_header() { let actual = nu!( @@ -20,11 +17,8 @@ fn headers_uses_first_row_as_header() { assert_eq!(actual.out, "r1c0r2c0") } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn headers_adds_missing_column_name() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/help.rs b/crates/nu-command/tests/commands/help.rs index e62badeade..0105318725 100644 --- a/crates/nu-command/tests/commands/help.rs +++ b/crates/nu-command/tests/commands/help.rs @@ -15,11 +15,8 @@ fn help_commands_length() { assert!(is_positive); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn help_generate_docs_length() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/histogram.rs b/crates/nu-command/tests/commands/histogram.rs index 948cecd75e..1b799f0f37 100644 --- a/crates/nu-command/tests/commands/histogram.rs +++ b/crates/nu-command/tests/commands/histogram.rs @@ -2,11 +2,8 @@ use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; use nu_test_support::playground::Playground; use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn summarizes_by_column_given() { Playground::setup("histogram_test_1", |dirs, sandbox| { @@ -38,11 +35,8 @@ fn summarizes_by_column_given() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn summarizes_by_values() { Playground::setup("histogram_test_2", |dirs, sandbox| { @@ -71,11 +65,8 @@ fn summarizes_by_values() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn help() { Playground::setup("histogram_test_3", |dirs, _sandbox| { @@ -105,11 +96,8 @@ fn help() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn count() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/into_filesize.rs b/crates/nu-command/tests/commands/into_filesize.rs index 26ab4e7d10..40edb39e94 100644 --- a/crates/nu-command/tests/commands/into_filesize.rs +++ b/crates/nu-command/tests/commands/into_filesize.rs @@ -33,11 +33,7 @@ fn into_filesize_str() { "# )); -<<<<<<< HEAD - assert!(actual.out.contains("2.0 KB")); -======= assert!(actual.out.contains("2.0 KiB")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -45,21 +41,12 @@ fn into_filesize_str_newline() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - '2000 -' | into filesize - "# - )); - - assert!(actual.out.contains("2.0 KB")); -======= "2000 " | into filesize "# )); assert!(actual.out.contains("2.0 KiB")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -67,15 +54,6 @@ fn into_filesize_str_many_newlines() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - '2000 - -' | into filesize - "# - )); - - assert!(actual.out.contains("2.0 KB")); -======= "2000 " | into filesize @@ -83,7 +61,6 @@ fn into_filesize_str_many_newlines() { )); assert!(actual.out.contains("2.0 KiB")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -91,17 +68,9 @@ fn into_filesize_filesize() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - 3kb | into filesize - "# - )); - - assert!(actual.out.contains("3.0 KB")); -======= 3kib | into filesize "# )); assert!(actual.out.contains("3.0 KiB")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/commands/into_int.rs b/crates/nu-command/tests/commands/into_int.rs new file mode 100644 index 0000000000..dbb20a1c7d --- /dev/null +++ b/crates/nu-command/tests/commands/into_int.rs @@ -0,0 +1,37 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn into_int_filesize() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo 1kb | into int | each { $it / 1000 } + "# + )); + + assert!(actual.out.contains('1')); +} + +#[test] +fn into_int_filesize2() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo 1kib | into int | each { $it / 1024 } + "# + )); + + assert!(actual.out.contains('1')); +} + +#[test] +fn into_int_int() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo 1024 | into int | each { $it / 1024 } + "# + )); + + assert!(actual.out.contains('1')); +} diff --git a/crates/nu-command/tests/commands/keep/mod.rs b/crates/nu-command/tests/commands/keep/mod.rs new file mode 100644 index 0000000000..a267c23529 --- /dev/null +++ b/crates/nu-command/tests/commands/keep/mod.rs @@ -0,0 +1,3 @@ +mod rows; +mod until; +mod while_; diff --git a/crates/nu-command/tests/commands/keep/rows.rs b/crates/nu-command/tests/commands/keep/rows.rs new file mode 100644 index 0000000000..84df113770 --- /dev/null +++ b/crates/nu-command/tests/commands/keep/rows.rs @@ -0,0 +1,31 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn rows() { + Playground::setup("keep_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "caballeros.csv", + r#" + name,lucky_code + AndrΓ©s,1 + Jonathan,1 + Jason,2 + Yehuda,1 + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open caballeros.csv + | keep 3 + | get lucky_code + | math sum + "# + )); + + assert_eq!(actual.out, "4"); + }) +} diff --git a/crates/nu-command/tests/commands/keep/until.rs b/crates/nu-command/tests/commands/keep/until.rs index e4be744ea7..b878e720ab 100644 --- a/crates/nu-command/tests/commands/keep/until.rs +++ b/crates/nu-command/tests/commands/keep/until.rs @@ -10,11 +10,7 @@ fn condition_is_met() { r#" CHICKEN SUMMARY report date: April 29th, 2020 -------------------------------------------------------------------- -<<<<<<< HEAD - Chicken Collection,29/04/2020,30/04/2020,31/04/2020, -======= Chicken Collection,29/04/2020,30/04/2020,31/04/2020 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce Yellow Chickens,,, AndrΓ©s,1,1,1 Jonathan,1,1,1 @@ -37,16 +33,6 @@ fn condition_is_met() { cwd: dirs.test(), pipeline( r#" open --raw caballeros.txt -<<<<<<< HEAD - | lines - | skip 2 - | split column ',' - | headers - | skip while "Chicken Collection" != "Blue Chickens" - | keep until "Chicken Collection" == "Red Chickens" - | skip 1 - | str to-int "31/04/2020" -======= | lines | skip 2 | str trim @@ -56,7 +42,6 @@ fn condition_is_met() { | keep until "Chicken Collection" == "Red Chickens" | skip 1 | into int "31/04/2020" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | get "31/04/2020" | math sum "# diff --git a/crates/nu-command/tests/commands/keep/while_.rs b/crates/nu-command/tests/commands/keep/while_.rs index c884a84029..72819e6c04 100644 --- a/crates/nu-command/tests/commands/keep/while_.rs +++ b/crates/nu-command/tests/commands/keep/while_.rs @@ -10,11 +10,7 @@ fn condition_is_met() { r#" CHICKEN SUMMARY report date: April 29th, 2020 -------------------------------------------------------------------- -<<<<<<< HEAD - Chicken Collection,29/04/2020,30/04/2020,31/04/2020, -======= Chicken Collection,29/04/2020,30/04/2020,31/04/2020 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce Yellow Chickens,,, AndrΓ©s,1,1,1 Jonathan,1,1,1 @@ -37,15 +33,6 @@ fn condition_is_met() { cwd: dirs.test(), pipeline( r#" open --raw caballeros.txt -<<<<<<< HEAD - | lines - | skip 2 - | split column ',' - | headers - | skip 1 - | keep while "Chicken Collection" != "Blue Chickens" - | str to-int "31/04/2020" -======= | lines | skip 2 | str trim @@ -54,7 +41,6 @@ fn condition_is_met() { | skip 1 | keep while "Chicken Collection" != "Blue Chickens" | into int "31/04/2020" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | get "31/04/2020" | math sum "# diff --git a/crates/nu-command/tests/commands/last.rs b/crates/nu-command/tests/commands/last.rs new file mode 100644 index 0000000000..b5acbb99ec --- /dev/null +++ b/crates/nu-command/tests/commands/last.rs @@ -0,0 +1,66 @@ +use nu_test_support::fs::Stub::EmptyFile; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn gets_the_last_row() { + let actual = nu!( + cwd: "tests/fixtures/formats", + "ls | sort-by name | last 1 | get name | str trim" + ); + + assert_eq!(actual.out, "utf16.ini"); +} + +#[test] +fn gets_last_rows_by_amount() { + Playground::setup("last_test_1", |dirs, sandbox| { + sandbox.with_files(vec![ + EmptyFile("los.txt"), + EmptyFile("tres.txt"), + EmptyFile("amigos.txt"), + EmptyFile("arepas.clu"), + ]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls + | last 3 + | length + "# + )); + + assert_eq!(actual.out, "3"); + }) +} + +#[test] +fn gets_last_row_when_no_amount_given() { + Playground::setup("last_test_2", |dirs, sandbox| { + sandbox.with_files(vec![EmptyFile("caballeros.txt"), EmptyFile("arepas.clu")]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls + | last + | length + "# + )); + + assert_eq!(actual.out, "1"); + }) +} + +#[test] +fn requests_more_rows_than_table_has() { + let actual = nu!( + cwd: ".", pipeline( + r#" + date | last 50 | length + "# + )); + + assert_eq!(actual.out, "1"); +} diff --git a/crates/nu-command/tests/commands/length.rs b/crates/nu-command/tests/commands/length.rs new file mode 100644 index 0000000000..9c5f51e9d7 --- /dev/null +++ b/crates/nu-command/tests/commands/length.rs @@ -0,0 +1,25 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn length_columns_in_cal_table() { + let actual = nu!( + cwd: ".", pipeline( + r#" + cal | length -c + "# + )); + + assert_eq!(actual.out, "7"); +} + +#[test] +fn length_columns_no_rows() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo [] | length -c + "# + )); + + assert_eq!(actual.out, "0"); +} diff --git a/crates/nu-command/tests/commands/lines.rs b/crates/nu-command/tests/commands/lines.rs index 17bb35734d..fcdb545c8d 100644 --- a/crates/nu-command/tests/commands/lines.rs +++ b/crates/nu-command/tests/commands/lines.rs @@ -27,11 +27,7 @@ fn lines_proper_buffering() { open lines_test.txt -r | lines | str length -<<<<<<< HEAD - | to json -======= | to json -r ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -50,9 +46,5 @@ fn lines_multi_value_split() { "# )); -<<<<<<< HEAD - assert_eq!(actual.out, "5"); -======= assert_eq!(actual.out, "6"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/commands/ls.rs b/crates/nu-command/tests/commands/ls.rs index f4f62dc309..91f9a1393f 100644 --- a/crates/nu-command/tests/commands/ls.rs +++ b/crates/nu-command/tests/commands/ls.rs @@ -88,11 +88,7 @@ fn lists_all_files_in_directories_from_stream() { r#" echo dir_a dir_b | each { ls $it } -<<<<<<< HEAD - | length -======= | flatten | length ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -304,22 +300,14 @@ fn list_all_columns() { // Normal Operation let actual = nu!( cwd: dirs.test(), -<<<<<<< HEAD - "ls | get | to md" -======= "ls | columns | to md" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); let expected = ["name", "type", "size", "modified"].join(""); assert_eq!(actual.out, expected, "column names are incorrect for ls"); // Long let actual = nu!( cwd: dirs.test(), -<<<<<<< HEAD - "ls -l | get | to md" -======= "ls -l | columns | to md" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); let expected = { #[cfg(unix)] @@ -328,17 +316,10 @@ fn list_all_columns() { "name", "type", "target", -<<<<<<< HEAD - "num_links", - "inode", - "readonly", - "mode", -======= "readonly", "mode", "num_links", "inode", ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "uid", "group", "size", diff --git a/crates/nu-command/tests/commands/math/avg.rs b/crates/nu-command/tests/commands/math/avg.rs index 787fed725a..3ad0709bda 100644 --- a/crates/nu-command/tests/commands/math/avg.rs +++ b/crates/nu-command/tests/commands/math/avg.rs @@ -18,15 +18,8 @@ fn can_average_numbers() { fn can_average_bytes() { let actual = nu!( cwd: "tests/fixtures/formats", -<<<<<<< HEAD - "ls | sort-by name | skip 1 | first 2 | get size | math avg | format \"{$it}\" " - ); - - assert_eq!(actual.out, "1.6 KB"); -======= "ls | sort-by name | skip 1 | first 2 | get size | math avg | to json -r" ); assert_eq!(actual.out, "1600"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/commands/math/eval.rs b/crates/nu-command/tests/commands/math/eval.rs index 74072ee434..14c83c6ea6 100644 --- a/crates/nu-command/tests/commands/math/eval.rs +++ b/crates/nu-command/tests/commands/math/eval.rs @@ -1,10 +1,7 @@ use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn evaluates_two_plus_two() { let actual = nu!( @@ -17,11 +14,8 @@ fn evaluates_two_plus_two() { assert!(actual.out.contains("4.0")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn evaluates_two_to_the_power_four() { let actual = nu!( @@ -34,11 +28,8 @@ fn evaluates_two_to_the_power_four() { assert!(actual.out.contains("16.0")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn evaluates_three_multiplied_by_five() { let actual = nu!( @@ -51,11 +42,8 @@ fn evaluates_three_multiplied_by_five() { assert!(actual.out.contains("15.0")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn evaluates_twenty_four_divided_by_two() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/math/median.rs b/crates/nu-command/tests/commands/math/median.rs new file mode 100644 index 0000000000..7509fe8f43 --- /dev/null +++ b/crates/nu-command/tests/commands/math/median.rs @@ -0,0 +1,40 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn median_numbers_with_even_rows() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo [10 6 19 21 4] + | math median + "# + )); + + assert_eq!(actual.out, "10") +} + +#[test] +fn median_numbers_with_odd_rows() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo [3 8 9 12 12 15] + | math median + "# + )); + + assert_eq!(actual.out, "10.5") +} + +#[test] +fn median_mixed_numbers() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo [-11.5 -13.5 10] + | math median + "# + )); + + assert_eq!(actual.out, "-11.5") +} diff --git a/crates/nu-command/tests/commands/math/mod.rs b/crates/nu-command/tests/commands/math/mod.rs index 463ced2224..01a60556ab 100644 --- a/crates/nu-command/tests/commands/math/mod.rs +++ b/crates/nu-command/tests/commands/math/mod.rs @@ -236,21 +236,6 @@ fn duration_math_with_negative() { } #[test] -<<<<<<< HEAD -fn duration_math_shell_error_on_big_numbers() { - let actual = nu!( - cwd: "tests/fixtures/formats", pipeline( - r#" - (date now) + 100000000000000day - "# - )); - - assert!(actual.err.contains("Duration overflow")); -} - -#[test] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn compound_comparison() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( @@ -279,19 +264,11 @@ fn compound_where() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo '[{"a": 1, "b": 1}, {"a": 2, "b": 1}, {"a": 2, "b": 2}]' | from json | where a == 2 && b == 1 | to json - "# - )); - - assert_eq!(actual.out, r#"{"a":2,"b":1}"#); -======= echo '[{"a": 1, "b": 1}, {"a": 2, "b": 1}, {"a": 2, "b": 2}]' | from json | where a == 2 && b == 1 | to json -r "# )); assert_eq!(actual.out, r#"[{"a": 2,"b": 1}]"#); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -299,17 +276,9 @@ fn compound_where_paren() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo '[{"a": 1, "b": 1}, {"a": 2, "b": 1}, {"a": 2, "b": 2}]' | from json | where ($it.a == 2 && $it.b == 1) || $it.b == 2 | to json - "# - )); - - assert_eq!(actual.out, r#"[{"a":2,"b":1},{"a":2,"b":2}]"#); -======= echo '[{"a": 1, "b": 1}, {"a": 2, "b": 1}, {"a": 2, "b": 2}]' | from json | where ($it.a == 2 && $it.b == 1) || $it.b == 2 | to json -r "# )); assert_eq!(actual.out, r#"[{"a": 2,"b": 1},{"a": 2,"b": 2}]"#); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/commands/math/round.rs b/crates/nu-command/tests/commands/math/round.rs new file mode 100644 index 0000000000..2bec436a64 --- /dev/null +++ b/crates/nu-command/tests/commands/math/round.rs @@ -0,0 +1,21 @@ +use nu_test_support::nu; + +#[test] +fn can_round_very_large_numbers() { + let actual = nu!( + cwd: ".", + "echo 18.1372544780074142289927665486772012345 | math round" + ); + + assert_eq!(actual.out, "18") +} + +#[test] +fn can_round_very_large_numbers_with_precision() { + let actual = nu!( + cwd: ".", + "echo 18.13725447800741422899276654867720121457878988 | math round -p 10" + ); + + assert_eq!(actual.out, "18.137254478") +} diff --git a/crates/nu-command/tests/commands/math/sqrt.rs b/crates/nu-command/tests/commands/math/sqrt.rs index 125e80752b..7d779d2354 100644 --- a/crates/nu-command/tests/commands/math/sqrt.rs +++ b/crates/nu-command/tests/commands/math/sqrt.rs @@ -1,10 +1,7 @@ use nu_test_support::nu; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn can_sqrt_numbers() { let actual = nu!( @@ -15,11 +12,8 @@ fn can_sqrt_numbers() { assert_eq!(actual.out, "3.914213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn can_sqrt_irrational() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/math/sum.rs b/crates/nu-command/tests/commands/math/sum.rs index 2b394128d4..bb78e91e16 100644 --- a/crates/nu-command/tests/commands/math/sum.rs +++ b/crates/nu-command/tests/commands/math/sum.rs @@ -75,11 +75,8 @@ fn compute_sum_of_table() -> Result<(), String> { Ok(()) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn sum_of_a_row_containing_a_table_is_an_error() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/merge.rs b/crates/nu-command/tests/commands/merge.rs index 9c5e383169..384a1d1c8d 100644 --- a/crates/nu-command/tests/commands/merge.rs +++ b/crates/nu-command/tests/commands/merge.rs @@ -2,11 +2,8 @@ use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; use nu_test_support::playground::Playground; use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn row() { Playground::setup("merge_test_1", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/mkdir.rs b/crates/nu-command/tests/commands/mkdir.rs new file mode 100644 index 0000000000..ddb3b08560 --- /dev/null +++ b/crates/nu-command/tests/commands/mkdir.rs @@ -0,0 +1,84 @@ +use nu_test_support::fs::files_exist_at; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; +use std::path::Path; + +#[test] +fn creates_directory() { + Playground::setup("mkdir_test_1", |dirs, _| { + nu!( + cwd: dirs.test(), + "mkdir my_new_directory" + ); + + let expected = dirs.test().join("my_new_directory"); + + assert!(expected.exists()); + }) +} + +#[test] +fn accepts_and_creates_directories() { + Playground::setup("mkdir_test_2", |dirs, _| { + nu!( + cwd: dirs.test(), + "mkdir dir_1 dir_2 dir_3" + ); + + assert!(files_exist_at( + vec![Path::new("dir_1"), Path::new("dir_2"), Path::new("dir_3")], + dirs.test() + )); + }) +} + +#[test] +fn creates_intermediary_directories() { + Playground::setup("mkdir_test_3", |dirs, _| { + nu!( + cwd: dirs.test(), + "mkdir some_folder/another/deeper_one" + ); + + let expected = dirs.test().join("some_folder/another/deeper_one"); + + assert!(expected.exists()); + }) +} + +#[test] +fn create_directory_two_parents_up_using_multiple_dots() { + Playground::setup("mkdir_test_4", |dirs, sandbox| { + sandbox.within("foo").mkdir("bar"); + + nu!( + cwd: dirs.test().join("foo/bar"), + "mkdir .../boo" + ); + + let expected = dirs.test().join("boo"); + + assert!(expected.exists()); + }) +} + +#[test] +fn show_created_paths() { + Playground::setup("mkdir_test_2", |dirs, _| { + let actual = nu!( + cwd: dirs.test(), + pipeline( + r#" + mkdir -s dir_1 dir_2 dir_3 + | length + "# + )); + + assert!(files_exist_at( + vec![Path::new("dir_1"), Path::new("dir_2"), Path::new("dir_3")], + dirs.test() + )); + + assert_eq!(actual.out, "3"); + }) +} diff --git a/crates/nu-command/tests/commands/mod.rs b/crates/nu-command/tests/commands/mod.rs index 7ae058a505..8db5a5af3b 100644 --- a/crates/nu-command/tests/commands/mod.rs +++ b/crates/nu-command/tests/commands/mod.rs @@ -4,10 +4,6 @@ mod append; mod cal; mod cd; mod compact; -<<<<<<< HEAD -mod config; -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce mod cp; mod def; mod default; @@ -27,10 +23,6 @@ mod hash_; mod headers; mod help; mod histogram; -<<<<<<< HEAD -mod insert; -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce mod into_filesize; mod into_int; mod keep; @@ -42,17 +34,10 @@ mod math; mod merge; mod mkdir; mod move_; -<<<<<<< HEAD -mod open; -mod parse; -mod path; -mod pathvar; -======= mod nth; mod open; mod parse; mod path; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce mod prepend; mod random; mod range; diff --git a/crates/nu-command/tests/commands/move_/column.rs b/crates/nu-command/tests/commands/move_/column.rs index a40d14a1c9..610b0390f3 100644 --- a/crates/nu-command/tests/commands/move_/column.rs +++ b/crates/nu-command/tests/commands/move_/column.rs @@ -34,11 +34,8 @@ fn moves_a_column_before() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn moves_columns_before() { Playground::setup("move_column_test_2", |dirs, sandbox| { @@ -73,11 +70,8 @@ fn moves_columns_before() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn moves_a_column_after() { Playground::setup("move_column_test_3", |dirs, sandbox| { @@ -113,11 +107,8 @@ fn moves_a_column_after() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn moves_columns_after() { Playground::setup("move_column_test_4", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/move_/mod.rs b/crates/nu-command/tests/commands/move_/mod.rs new file mode 100644 index 0000000000..58d0a7f6cd --- /dev/null +++ b/crates/nu-command/tests/commands/move_/mod.rs @@ -0,0 +1,2 @@ +mod column; +mod mv; diff --git a/crates/nu-command/tests/commands/move_/mv.rs b/crates/nu-command/tests/commands/move_/mv.rs index 9a70a5965a..1050a5a331 100644 --- a/crates/nu-command/tests/commands/move_/mv.rs +++ b/crates/nu-command/tests/commands/move_/mv.rs @@ -195,11 +195,8 @@ fn moves_a_directory_with_files() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_source_doesnt_exist() { Playground::setup("mv_test_10", |dirs, sandbox| { @@ -212,11 +209,8 @@ fn errors_if_source_doesnt_exist() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_destination_doesnt_exist() { Playground::setup("mv_test_10_1", |dirs, sandbox| { @@ -231,11 +225,8 @@ fn errors_if_destination_doesnt_exist() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_multiple_sources_but_destination_not_a_directory() { Playground::setup("mv_test_10_2", |dirs, sandbox| { @@ -256,11 +247,8 @@ fn errors_if_multiple_sources_but_destination_not_a_directory() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_renaming_directory_to_an_existing_file() { Playground::setup("mv_test_10_3", |dirs, sandbox| { @@ -277,11 +265,8 @@ fn errors_if_renaming_directory_to_an_existing_file() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_moving_to_itself() { Playground::setup("mv_test_10_4", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/nth.rs b/crates/nu-command/tests/commands/nth.rs index 95c9672eb2..bd396fea8f 100644 --- a/crates/nu-command/tests/commands/nth.rs +++ b/crates/nu-command/tests/commands/nth.rs @@ -1,10 +1,7 @@ -<<<<<<< HEAD -======= use nu_test_support::fs::Stub::EmptyFile; use nu_test_support::playground::Playground; use nu_test_support::{nu, pipeline}; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn selects_a_row() { Playground::setup("nth_test_1", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/open.rs b/crates/nu-command/tests/commands/open.rs index c747ec84ac..ea11ffd01e 100644 --- a/crates/nu-command/tests/commands/open.rs +++ b/crates/nu-command/tests/commands/open.rs @@ -185,22 +185,6 @@ fn parses_json() { } #[test] -<<<<<<< HEAD -fn parses_xml() { - let actual = nu!( - cwd: "tests/fixtures/formats", - "open jonathan.xml | get rss.children.channel.children | get item.children | get link.children.0" - ); - - assert_eq!( - actual.out, - "http://www.jonathanturner.org/2015/10/off-to-new-adventures.html" - ) -} - -#[test] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn parses_ini() { let actual = nu!( cwd: "tests/fixtures/formats", @@ -214,21 +198,14 @@ fn parses_ini() { fn parses_utf16_ini() { let actual = nu!( cwd: "tests/fixtures/formats", -<<<<<<< HEAD - "open utf16.ini | rename info | get info | get IconIndex" -======= "open ./utf16.ini --raw | decode utf-16 | from ini | rename info | get info | get IconIndex" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "-236") } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_file_not_found() { let actual = nu!( @@ -244,11 +221,8 @@ fn errors_if_file_not_found() { ); } -<<<<<<< HEAD -======= // FIXME: jt: I think `open` on a directory is confusing. We should make discuss this one a bit more #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn open_dir_is_ls() { Playground::setup("open_dir", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/parse.rs b/crates/nu-command/tests/commands/parse.rs index 579bb23643..40d7fc917f 100644 --- a/crates/nu-command/tests/commands/parse.rs +++ b/crates/nu-command/tests/commands/parse.rs @@ -5,11 +5,8 @@ use nu_test_support::{nu, pipeline}; mod simple { use super::*; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn extracts_fields_from_the_given_the_pattern() { Playground::setup("parse_test_1", |dirs, sandbox| { @@ -86,11 +83,8 @@ mod simple { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_when_missing_closing_brace() { Playground::setup("parse_test_regex_5", |dirs, _sandbox| { diff --git a/crates/nu-command/tests/commands/path/basename.rs b/crates/nu-command/tests/commands/path/basename.rs new file mode 100644 index 0000000000..a16c8202c9 --- /dev/null +++ b/crates/nu-command/tests/commands/path/basename.rs @@ -0,0 +1,83 @@ +use nu_test_support::{nu, pipeline}; + +use super::join_path_sep; + +#[test] +fn returns_basename_of_empty_input() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "" + | path basename + "# + )); + + assert_eq!(actual.out, ""); +} + +#[test] +fn replaces_basename_of_empty_input() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "" + | path basename -r newname.txt + "# + )); + + assert_eq!(actual.out, "newname.txt"); +} + +#[test] +fn returns_basename_of_path_ending_with_dot() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/file.txt/." + | path basename + "# + )); + + assert_eq!(actual.out, "file.txt"); +} + +#[test] +fn replaces_basename_of_path_ending_with_dot() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/file.txt/." + | path basename -r viking.txt + "# + )); + + let expected = join_path_sep(&["some", "viking.txt"]); + assert_eq!(actual.out, expected); +} + +#[test] +fn returns_basename_of_path_ending_with_double_dot() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/file.txt/.." + | path basename + "# + )); + + assert_eq!(actual.out, ""); +} + +#[test] +fn replaces_basename_of_path_ending_with_double_dot() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/file.txt/.." + | path basename -r eggs + "# + )); + + let expected = join_path_sep(&["some/file.txt/..", "eggs"]); + assert_eq!(actual.out, expected); +} diff --git a/crates/nu-command/tests/commands/path/dirname.rs b/crates/nu-command/tests/commands/path/dirname.rs new file mode 100644 index 0000000000..a935c1fb34 --- /dev/null +++ b/crates/nu-command/tests/commands/path/dirname.rs @@ -0,0 +1,137 @@ +use nu_test_support::{nu, pipeline}; + +use super::join_path_sep; + +#[test] +fn returns_dirname_of_empty_input() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "" + | path dirname + "# + )); + + assert_eq!(actual.out, ""); +} + +#[test] +fn replaces_dirname_of_empty_input() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "" + | path dirname -r newdir + "# + )); + + assert_eq!(actual.out, "newdir"); +} + +#[test] +fn returns_dirname_of_path_ending_with_dot() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/dir/." + | path dirname + "# + )); + + assert_eq!(actual.out, "some"); +} + +#[test] +fn replaces_dirname_of_path_ending_with_dot() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/dir/." + | path dirname -r eggs + "# + )); + + let expected = join_path_sep(&["eggs", "dir"]); + assert_eq!(actual.out, expected); +} + +#[test] +fn returns_dirname_of_path_ending_with_double_dot() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/dir/.." + | path dirname + "# + )); + + assert_eq!(actual.out, "some/dir"); +} + +#[test] +fn replaces_dirname_of_path_with_double_dot() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/dir/.." + | path dirname -r eggs + "# + )); + + let expected = join_path_sep(&["eggs", ".."]); + assert_eq!(actual.out, expected); +} + +#[test] +fn returns_dirname_of_zero_levels() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/dir/with/spam.txt" + | path dirname -n 0 + "# + )); + + assert_eq!(actual.out, "some/dir/with/spam.txt"); +} + +#[test] +fn replaces_dirname_of_zero_levels_with_empty_string() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/dir/with/spam.txt" + | path dirname -n 0 -r "" + "# + )); + + assert_eq!(actual.out, ""); +} + +#[test] +fn replaces_dirname_of_more_levels() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/dir/with/spam.txt" + | path dirname -r eggs -n 2 + "# + )); + + let expected = join_path_sep(&["eggs", "with/spam.txt"]); + assert_eq!(actual.out, expected); +} + +#[test] +fn replaces_dirname_of_way_too_many_levels() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "some/dir/with/spam.txt" + | path dirname -r eggs -n 999 + "# + )); + + let expected = join_path_sep(&["eggs", "some/dir/with/spam.txt"]); + assert_eq!(actual.out, expected); +} diff --git a/crates/nu-command/tests/commands/path/exists.rs b/crates/nu-command/tests/commands/path/exists.rs index 59ab0dc6f5..0ab51ac939 100644 --- a/crates/nu-command/tests/commands/path/exists.rs +++ b/crates/nu-command/tests/commands/path/exists.rs @@ -2,11 +2,8 @@ use nu_test_support::fs::Stub::EmptyFile; use nu_test_support::nu; use nu_test_support::playground::Playground; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn checks_if_existing_file_exists() { Playground::setup("path_exists_1", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/path/expand.rs b/crates/nu-command/tests/commands/path/expand.rs new file mode 100644 index 0000000000..08ca9dc587 --- /dev/null +++ b/crates/nu-command/tests/commands/path/expand.rs @@ -0,0 +1,78 @@ +use nu_test_support::fs::Stub::EmptyFile; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +use std::path::PathBuf; + +#[test] +fn expands_path_with_dot() { + Playground::setup("path_expand_1", |dirs, sandbox| { + sandbox + .within("menu") + .with_files(vec![EmptyFile("spam.txt")]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + echo "menu/./spam.txt" + | path expand + "# + )); + + let expected = dirs.test.join("menu").join("spam.txt"); + assert_eq!(PathBuf::from(actual.out), expected); + }) +} + +#[test] +fn expands_path_with_double_dot() { + Playground::setup("path_expand_2", |dirs, sandbox| { + sandbox + .within("menu") + .with_files(vec![EmptyFile("spam.txt")]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + echo "menu/../menu/spam.txt" + | path expand + "# + )); + + let expected = dirs.test.join("menu").join("spam.txt"); + assert_eq!(PathBuf::from(actual.out), expected); + }) +} + +#[cfg(windows)] +mod windows { + use super::*; + + #[test] + fn expands_path_with_tilde_backward_slash() { + Playground::setup("path_expand_2", |dirs, _| { + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + echo "~\tmp.txt" | path expand + "# + )); + + assert!(!PathBuf::from(actual.out).starts_with("~")); + }) + } + + #[test] + fn win_expands_path_with_tilde_forward_slash() { + Playground::setup("path_expand_2", |dirs, _| { + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + echo "~/tmp.txt" | path expand + "# + )); + + assert!(!PathBuf::from(actual.out).starts_with("~")); + }) + } +} diff --git a/crates/nu-command/tests/commands/path/join.rs b/crates/nu-command/tests/commands/path/join.rs new file mode 100644 index 0000000000..b7ffa73538 --- /dev/null +++ b/crates/nu-command/tests/commands/path/join.rs @@ -0,0 +1,59 @@ +use nu_test_support::{nu, pipeline}; + +use super::join_path_sep; + +#[test] +fn returns_path_joined_with_column_path() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo [ [name]; [eggs] ] + | path join spam.txt -c [ name ] + | get name + "# + )); + + let expected = join_path_sep(&["eggs", "spam.txt"]); + assert_eq!(actual.out, expected); +} + +#[test] +fn returns_path_joined_from_list() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo [ home viking spam.txt ] + | path join + "# + )); + + let expected = join_path_sep(&["home", "viking", "spam.txt"]); + assert_eq!(actual.out, expected); +} + +#[test] +fn appends_slash_when_joined_with_empty_path() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "/some/dir" + | path join '' + "# + )); + + let expected = join_path_sep(&["/some/dir", ""]); + assert_eq!(actual.out, expected); +} + +#[test] +fn returns_joined_path_when_joining_empty_path() { + let actual = nu!( + cwd: "tests", pipeline( + r#" + echo "" + | path join foo.txt + "# + )); + + assert_eq!(actual.out, "foo.txt"); +} diff --git a/crates/nu-command/tests/commands/path/mod.rs b/crates/nu-command/tests/commands/path/mod.rs new file mode 100644 index 0000000000..c836c5691d --- /dev/null +++ b/crates/nu-command/tests/commands/path/mod.rs @@ -0,0 +1,34 @@ +mod basename; +mod dirname; +mod exists; +mod expand; +mod join; +mod parse; +mod split; +mod type_; + +use std::path::MAIN_SEPARATOR; + +/// Helper function that joins string literals with '/' or '\', based on host OS +fn join_path_sep(pieces: &[&str]) -> String { + let sep_string = String::from(MAIN_SEPARATOR); + pieces.join(&sep_string) +} + +#[cfg(windows)] +#[test] +fn joins_path_on_windows() { + let pieces = ["sausage", "bacon", "spam"]; + let actual = join_path_sep(&pieces); + + assert_eq!(&actual, "sausage\\bacon\\spam"); +} + +#[cfg(not(windows))] +#[test] +fn joins_path_on_other_than_windows() { + let pieces = ["sausage", "bacon", "spam"]; + let actual = join_path_sep(&pieces); + + assert_eq!(&actual, "sausage/bacon/spam"); +} diff --git a/crates/nu-command/tests/commands/path/parse.rs b/crates/nu-command/tests/commands/path/parse.rs index 0afa69b5a5..4ca1bf1e02 100644 --- a/crates/nu-command/tests/commands/path/parse.rs +++ b/crates/nu-command/tests/commands/path/parse.rs @@ -114,11 +114,8 @@ fn parses_column_path_extension() { assert_eq!(actual.out, "png"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn parses_into_correct_number_of_columns() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/path/split.rs b/crates/nu-command/tests/commands/path/split.rs index 95492d94a0..ffd51cd434 100644 --- a/crates/nu-command/tests/commands/path/split.rs +++ b/crates/nu-command/tests/commands/path/split.rs @@ -17,11 +17,7 @@ fn splits_correctly_single_path() { let actual = nu!( cwd: "tests", pipeline( r#" -<<<<<<< HEAD - echo ['home/viking/spam.txt'] -======= 'home/viking/spam.txt' ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | path split | last "# @@ -43,10 +39,7 @@ fn splits_correctly_with_column_path() { ] | path split -c [ home barn ] | get barn -<<<<<<< HEAD -======= | flatten ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | length "# )); diff --git a/crates/nu-command/tests/commands/path/type_.rs b/crates/nu-command/tests/commands/path/type_.rs index 125dc74946..43a599558f 100644 --- a/crates/nu-command/tests/commands/path/type_.rs +++ b/crates/nu-command/tests/commands/path/type_.rs @@ -15,11 +15,8 @@ fn returns_type_of_missing_file() { assert_eq!(actual.out, ""); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn returns_type_of_existing_file() { Playground::setup("path_expand_1", |dirs, sandbox| { @@ -35,19 +32,12 @@ fn returns_type_of_existing_file() { "# )); -<<<<<<< HEAD - assert_eq!(actual.out, "Dir"); - }) -} - -======= assert_eq!(actual.out, "dir"); }) } // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn returns_type_of_existing_directory() { Playground::setup("path_expand_1", |dirs, sandbox| { @@ -63,10 +53,6 @@ fn returns_type_of_existing_directory() { "# )); -<<<<<<< HEAD - assert_eq!(actual.out, "File"); -======= assert_eq!(actual.out, "file"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }) } diff --git a/crates/nu-command/tests/commands/prepend.rs b/crates/nu-command/tests/commands/prepend.rs new file mode 100644 index 0000000000..1c872becba --- /dev/null +++ b/crates/nu-command/tests/commands/prepend.rs @@ -0,0 +1,29 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn adds_a_row_to_the_beginning() { + Playground::setup("prepend_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "los_tres_caballeros.txt", + r#" + AndrΓ©s N. Robalino + Jonathan Turner + Yehuda Katz + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open los_tres_caballeros.txt + | lines + | prepend "pollo loco" + | nth 0 + "# + )); + + assert_eq!(actual.out, "pollo loco"); + }) +} diff --git a/crates/nu-command/tests/commands/random/bool.rs b/crates/nu-command/tests/commands/random/bool.rs new file mode 100644 index 0000000000..862ba2840c --- /dev/null +++ b/crates/nu-command/tests/commands/random/bool.rs @@ -0,0 +1,16 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn generates_a_bool() { + let actual = nu!( + cwd: ".", pipeline( + r#" + random bool + "# + )); + + let output = actual.out; + let is_boolean_output = output == "true" || output == "false"; + + assert!(is_boolean_output); +} diff --git a/crates/nu-command/tests/commands/random/chars.rs b/crates/nu-command/tests/commands/random/chars.rs new file mode 100644 index 0000000000..c77f347364 --- /dev/null +++ b/crates/nu-command/tests/commands/random/chars.rs @@ -0,0 +1,14 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn generates_chars_of_specified_length() { + let actual = nu!( + cwd: ".", pipeline( + r#" + random chars -l 15 | size | get chars + "# + )); + + let result = actual.out; + assert_eq!(result, "15"); +} diff --git a/crates/nu-command/tests/commands/random/decimal.rs b/crates/nu-command/tests/commands/random/decimal.rs index 19650059da..74c064d10e 100644 --- a/crates/nu-command/tests/commands/random/decimal.rs +++ b/crates/nu-command/tests/commands/random/decimal.rs @@ -1,10 +1,7 @@ use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn generates_an_decimal() { let actual = nu!( @@ -17,11 +14,8 @@ fn generates_an_decimal() { assert!(actual.out.contains("42") || actual.out.contains("43")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn generates_55() { let actual = nu!( @@ -34,11 +28,8 @@ fn generates_55() { assert!(actual.out.contains("55")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn generates_0() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/random/dice.rs b/crates/nu-command/tests/commands/random/dice.rs new file mode 100644 index 0000000000..a056f07c9d --- /dev/null +++ b/crates/nu-command/tests/commands/random/dice.rs @@ -0,0 +1,13 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn rolls_4_roll() { + let actual = nu!( + cwd: ".", pipeline( + r#" + random dice -d 4 -s 10 | length + "# + )); + + assert_eq!(actual.out, "4"); +} diff --git a/crates/nu-command/tests/commands/random/integer.rs b/crates/nu-command/tests/commands/random/integer.rs index 645f2dd05c..9ca86ff261 100644 --- a/crates/nu-command/tests/commands/random/integer.rs +++ b/crates/nu-command/tests/commands/random/integer.rs @@ -24,11 +24,8 @@ fn generates_55() { assert!(actual.out.contains("55")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn generates_0() { let actual = nu!( diff --git a/crates/nu-command/tests/commands/random/mod.rs b/crates/nu-command/tests/commands/random/mod.rs new file mode 100644 index 0000000000..9b3bf6eb88 --- /dev/null +++ b/crates/nu-command/tests/commands/random/mod.rs @@ -0,0 +1,7 @@ +mod bool; +mod chars; +mod decimal; +mod dice; +mod integer; +#[cfg(feature = "uuid_crate")] +mod uuid; diff --git a/crates/nu-command/tests/commands/random/uuid.rs b/crates/nu-command/tests/commands/random/uuid.rs new file mode 100644 index 0000000000..725081383c --- /dev/null +++ b/crates/nu-command/tests/commands/random/uuid.rs @@ -0,0 +1,16 @@ +use nu_test_support::{nu, pipeline}; +use uuid_crate::Uuid; + +#[test] +fn generates_valid_uuid4() { + let actual = nu!( + cwd: ".", pipeline( + r#" + random uuid + "# + )); + + let result = Uuid::parse_str(actual.out.as_str()); + + assert!(result.is_ok()); +} diff --git a/crates/nu-command/tests/commands/range.rs b/crates/nu-command/tests/commands/range.rs new file mode 100644 index 0000000000..7aa3e4e66b --- /dev/null +++ b/crates/nu-command/tests/commands/range.rs @@ -0,0 +1,68 @@ +use nu_test_support::fs::Stub::EmptyFile; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn selects_a_row() { + Playground::setup("range_test_1", |dirs, sandbox| { + sandbox.with_files(vec![EmptyFile("notes.txt"), EmptyFile("tests.txt")]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls + | sort-by name + | range 0..0 + | get name + "# + )); + + assert_eq!(actual.out, "notes.txt"); + }); +} + +#[test] +fn selects_some_rows() { + Playground::setup("range_test_2", |dirs, sandbox| { + sandbox.with_files(vec![ + EmptyFile("notes.txt"), + EmptyFile("tests.txt"), + EmptyFile("persons.txt"), + ]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls + | get name + | range 1..2 + | length + "# + )); + + assert_eq!(actual.out, "2"); + }); +} + +#[test] +fn negative_indices() { + Playground::setup("range_test_negative_indices", |dirs, sandbox| { + sandbox.with_files(vec![ + EmptyFile("notes.txt"), + EmptyFile("tests.txt"), + EmptyFile("persons.txt"), + ]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + ls + | get name + | range (-1..) + | length + "# + )); + + assert_eq!(actual.out, "1"); + }); +} diff --git a/crates/nu-command/tests/commands/reduce.rs b/crates/nu-command/tests/commands/reduce.rs index 9e3115789c..b5584f979d 100644 --- a/crates/nu-command/tests/commands/reduce.rs +++ b/crates/nu-command/tests/commands/reduce.rs @@ -1,10 +1,7 @@ use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn reduce_table_column() { let actual = nu!( @@ -13,11 +10,7 @@ fn reduce_table_column() { echo "[{month:2,total:30}, {month:3,total:10}, {month:4,total:3}, {month:5,total:60}]" | from json | get total -<<<<<<< HEAD - | reduce -f 20 { $it + (math eval $"($acc)^1.05")} -======= | reduce -f 20 { $it.item + (math eval $"($item.acc)^1.05")} ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | into string -d 1 "# ) @@ -26,24 +19,15 @@ fn reduce_table_column() { assert_eq!(actual.out, "180.6"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn reduce_table_column_with_path() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - echo "[{month:2,total:30}, {month:3,total:10}, {month:4,total:3}, {month:5,total:60}]" - | from json - | reduce -f 20 { $it.total + (math eval $"($acc)^1.05")} -======= [{month:2,total:30}, {month:3,total:10}, {month:4,total:3}, {month:5,total:60}] | reduce -f 20 { $it.item.total + (math eval $"($item.acc)^1.05")} ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | into string -d 1 "# ) @@ -52,25 +36,15 @@ fn reduce_table_column_with_path() { assert_eq!(actual.out, "180.6"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn reduce_rows_example() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - echo a,b 1,2 3,4 - | split column , - | headers - | reduce -f 1.6 { $acc * ($it.a | str to-int) + ($it.b | str to-int) } -======= [[a,b]; [1,2] [3,4]] | reduce -f 1.6 { $it.acc * ($it.item.a | into int) + ($it.item.b | into int) } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ) ); @@ -78,22 +52,15 @@ fn reduce_rows_example() { assert_eq!(actual.out, "14.8"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn reduce_numbered_example() { let actual = nu!( cwd: ".", pipeline( r#" echo one longest three bar -<<<<<<< HEAD - | reduce -n { if ($it.item | str length) > ($acc.item | str length) {echo $it} {echo $acc}} -======= | reduce -n { if ($it.item.item | str length) > ($it.acc.item | str length) {echo $it.item} else {echo $it.acc}} ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | get index "# ) @@ -102,22 +69,15 @@ fn reduce_numbered_example() { assert_eq!(actual.out, "1"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn reduce_numbered_integer_addition_example() { let actual = nu!( cwd: ".", pipeline( r#" echo [1 2 3 4] -<<<<<<< HEAD - | reduce -n { $acc.item + $it.item } -======= | reduce -n { $it.acc.item + $it.item.item } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | get item "# ) @@ -126,11 +86,8 @@ fn reduce_numbered_integer_addition_example() { assert_eq!(actual.out, "10"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn folding_with_tables() { let actual = nu!( @@ -138,13 +95,8 @@ fn folding_with_tables() { r#" echo [10 20 30 40] | reduce -f [] { -<<<<<<< HEAD - with-env [value $it] { - echo $acc | append (10 * ($nu.env.value | str to-int)) -======= with-env [value $it.item] { echo $acc | append (10 * ($env.value | into int)) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } | math sum @@ -155,46 +107,29 @@ fn folding_with_tables() { assert_eq!(actual.out, "1000"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn error_reduce_fold_type_mismatch() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - echo a b c | reduce -f 0 { $acc + $it } -======= echo a b c | reduce -f 0 { $it.acc + $it.item } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ) ); -<<<<<<< HEAD - assert!(actual.err.contains("Coercion")); -} - -======= assert!(actual.err.contains("mismatch")); } // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn error_reduce_empty() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - reduce { $acc + $it } -======= reduce { $it.$acc + $it.item } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ) ); diff --git a/crates/nu-command/tests/commands/rename.rs b/crates/nu-command/tests/commands/rename.rs index 207ec809d3..1d5b35d479 100644 --- a/crates/nu-command/tests/commands/rename.rs +++ b/crates/nu-command/tests/commands/rename.rs @@ -61,11 +61,8 @@ fn keeps_remaining_original_names_given_less_new_names_than_total_original_names }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_no_columns_present() { Playground::setup("rename_test_3", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/reverse.rs b/crates/nu-command/tests/commands/reverse.rs new file mode 100644 index 0000000000..e994aa4927 --- /dev/null +++ b/crates/nu-command/tests/commands/reverse.rs @@ -0,0 +1,11 @@ +use nu_test_support::nu; + +#[test] +fn can_get_reverse_first() { + let actual = nu!( + cwd: "tests/fixtures/formats", + "ls | sort-by name | reverse | first 1 | get name | str trim " + ); + + assert_eq!(actual.out, "utf16.ini"); +} diff --git a/crates/nu-command/tests/commands/rm.rs b/crates/nu-command/tests/commands/rm.rs index 81a7473478..ddbe7180ca 100644 --- a/crates/nu-command/tests/commands/rm.rs +++ b/crates/nu-command/tests/commands/rm.rs @@ -121,11 +121,8 @@ fn removes_directory_contents_with_recursive_flag() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_attempting_to_delete_a_directory_with_content_without_recursive_flag() { Playground::setup("rm_test_6", |dirs, sandbox| { @@ -140,11 +137,8 @@ fn errors_if_attempting_to_delete_a_directory_with_content_without_recursive_fla }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_attempting_to_delete_single_dot_as_argument() { Playground::setup("rm_test_7", |dirs, _| { @@ -157,11 +151,8 @@ fn errors_if_attempting_to_delete_single_dot_as_argument() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn errors_if_attempting_to_delete_two_dot_as_argument() { Playground::setup("rm_test_8", |dirs, _| { @@ -292,11 +283,8 @@ fn no_errors_if_attempting_to_delete_non_existent_file_with_f_flag() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn rm_wildcard_keeps_dotfiles() { Playground::setup("rm_test_15", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/roll.rs b/crates/nu-command/tests/commands/roll.rs index 25276c1554..7230ecfb21 100644 --- a/crates/nu-command/tests/commands/roll.rs +++ b/crates/nu-command/tests/commands/roll.rs @@ -17,11 +17,8 @@ mod rows { ) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn roll_down_by_default() { let actual = nu!( @@ -35,11 +32,8 @@ mod rows { assert_eq!(actual.out, "HERE"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn can_roll_up() { let actual = nu!( @@ -72,11 +66,8 @@ mod columns { ) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn roll_left_by_default() { let actual = nu!( @@ -90,11 +81,8 @@ mod columns { assert_eq!(actual.out, "origin-stars-commit_author"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn can_roll_in_the_opposite_direction() { let actual = nu!( @@ -110,11 +98,8 @@ mod columns { struct ThirtieTwo<'a>(usize, &'a str); -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn can_roll_the_cells_only_keeping_the_header_names() { let four_bitstring = bitstring_to_nu_row_pipeline("00000100"); @@ -128,11 +113,8 @@ mod columns { assert_eq!(actual.out, expected_value.1); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn four_in_bitstring_left_shifted_with_three_bits_should_be_32_in_decimal() { let four_bitstring = "00000100"; @@ -185,11 +167,7 @@ mod columns { pipeline( r#" split chars -<<<<<<< HEAD - | each { str to-int } -======= | each { into int } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | rotate counter-clockwise _ | reject _ | rename bit1 bit2 bit3 bit4 bit5 bit6 bit7 bit8 diff --git a/crates/nu-command/tests/commands/rotate.rs b/crates/nu-command/tests/commands/rotate.rs index b3061d0e48..906f7d9833 100644 --- a/crates/nu-command/tests/commands/rotate.rs +++ b/crates/nu-command/tests/commands/rotate.rs @@ -1,10 +1,7 @@ use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn counter_clockwise() { let table = pipeline( diff --git a/crates/nu-command/tests/commands/save.rs b/crates/nu-command/tests/commands/save.rs index 56a4ccf6a5..7a82867ad9 100644 --- a/crates/nu-command/tests/commands/save.rs +++ b/crates/nu-command/tests/commands/save.rs @@ -48,11 +48,8 @@ fn writes_out_csv() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn save_append_will_create_file_if_not_exists() { Playground::setup("save_test_3", |dirs, sandbox| { diff --git a/crates/nu-command/tests/commands/select.rs b/crates/nu-command/tests/commands/select.rs index 7fd3239e1a..6415445267 100644 --- a/crates/nu-command/tests/commands/select.rs +++ b/crates/nu-command/tests/commands/select.rs @@ -22,11 +22,8 @@ fn regular_columns() { assert_eq!(actual.out, "Robalino"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn complex_nested_columns() { Playground::setup("select_test_2", |dirs, sandbox| { @@ -69,11 +66,8 @@ fn complex_nested_columns() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn allows_if_given_unknown_column_name_is_missing() { let actual = nu!(cwd: ".", pipeline( @@ -112,11 +106,8 @@ fn column_names_with_spaces() { assert_eq!(actual.out, "Robalino Jnth"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn ignores_duplicate_columns_selected() { let actual = nu!(cwd: ".", pipeline( diff --git a/crates/nu-command/tests/commands/semicolon.rs b/crates/nu-command/tests/commands/semicolon.rs new file mode 100644 index 0000000000..19e4a9cfe2 --- /dev/null +++ b/crates/nu-command/tests/commands/semicolon.rs @@ -0,0 +1,29 @@ +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn semicolon_allows_lhs_to_complete() { + Playground::setup("create_test_1", |dirs, _sandbox| { + let actual = nu!( + cwd: dirs.test(), + "touch i_will_be_created_semi.txt; echo done" + ); + + let path = dirs.test().join("i_will_be_created_semi.txt"); + + assert!(path.exists()); + assert_eq!(actual.out, "done"); + }) +} + +#[test] +fn semicolon_lhs_error_stops_processing() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + where 1 1; echo done + "# + )); + + assert!(!actual.out.contains("done")); +} diff --git a/crates/nu-command/tests/commands/skip/mod.rs b/crates/nu-command/tests/commands/skip/mod.rs new file mode 100644 index 0000000000..aa35de0702 --- /dev/null +++ b/crates/nu-command/tests/commands/skip/mod.rs @@ -0,0 +1,2 @@ +mod until; +mod while_; diff --git a/crates/nu-command/tests/commands/skip/until.rs b/crates/nu-command/tests/commands/skip/until.rs index 3fed3b251c..2003ed3c53 100644 --- a/crates/nu-command/tests/commands/skip/until.rs +++ b/crates/nu-command/tests/commands/skip/until.rs @@ -10,11 +10,7 @@ fn condition_is_met() { r#" CHICKEN SUMMARY report date: April 29th, 2020 -------------------------------------------------------------------- -<<<<<<< HEAD - Chicken Collection,29/04/2020,30/04/2020,31/04/2020, -======= Chicken Collection,29/04/2020,30/04/2020,31/04/2020 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce Yellow Chickens,,, AndrΓ©s,0,0,1 Jonathan,0,0,1 @@ -36,16 +32,6 @@ fn condition_is_met() { let actual = nu!( cwd: dirs.test(), pipeline( r#" -<<<<<<< HEAD - open --raw caballeros.txt - | lines - | skip 2 - | split column ',' - | headers - | skip until "Chicken Collection" == "Red Chickens" - | skip 1 - | str to-int "31/04/2020" -======= open --raw ./caballeros.txt | lines | skip 2 @@ -55,7 +41,6 @@ fn condition_is_met() { | skip until "Chicken Collection" == "Red Chickens" | skip 1 | into int "31/04/2020" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | get "31/04/2020" | math sum "# diff --git a/crates/nu-command/tests/commands/skip/while_.rs b/crates/nu-command/tests/commands/skip/while_.rs index a1b7415d6b..a2cad635fc 100644 --- a/crates/nu-command/tests/commands/skip/while_.rs +++ b/crates/nu-command/tests/commands/skip/while_.rs @@ -10,11 +10,7 @@ fn condition_is_met() { r#" CHICKEN SUMMARY report date: April 29th, 2020 -------------------------------------------------------------------- -<<<<<<< HEAD - Chicken Collection,29/04/2020,30/04/2020,31/04/2020, -======= Chicken Collection,29/04/2020,30/04/2020,31/04/2020 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce Yellow Chickens,,, AndrΓ©s,0,0,1 Jonathan,0,0,1 @@ -37,15 +33,6 @@ fn condition_is_met() { cwd: dirs.test(), pipeline( r#" open --raw caballeros.txt -<<<<<<< HEAD - | lines - | skip 2 - | split column ',' - | headers - | skip while "Chicken Collection" != "Red Chickens" - | skip 1 - | str to-int "31/04/2020" -======= | lines | skip 2 | str trim @@ -54,7 +41,6 @@ fn condition_is_met() { | skip while "Chicken Collection" != "Red Chickens" | skip 1 | into int "31/04/2020" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | get "31/04/2020" | math sum "# diff --git a/crates/nu-command/tests/commands/sort_by.rs b/crates/nu-command/tests/commands/sort_by.rs index d53f6ddd8a..e7eb57168c 100644 --- a/crates/nu-command/tests/commands/sort_by.rs +++ b/crates/nu-command/tests/commands/sort_by.rs @@ -1,10 +1,7 @@ use nu_test_support::{nu, pipeline}; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn by_column() { let actual = nu!( @@ -26,11 +23,8 @@ fn by_column() { assert_eq!(actual.out, "description"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn by_invalid_column() { let actual = nu!( @@ -53,11 +47,8 @@ fn by_invalid_column() { assert!(actual.err.contains("invalid column")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn by_invalid_types() { let actual = nu!( @@ -100,20 +91,12 @@ fn ls_sort_by_name_sensitive() { open sample-ls-output.json | sort-by name | select name -<<<<<<< HEAD - | to json - "# - )); - - let json_output = r#"[{"name":"B.txt"},{"name":"C"},{"name":"a.txt"}]"#; -======= | to json --raw "# )); //let json_output = r#"[{"name":"B.txt"},{"name":"C"},{"name":"a.txt"}]"#; let json_output = r#"[{"name": "B.txt"},{"name": "C"},{"name": "a.txt"}]"#; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.out, json_output); } @@ -126,20 +109,11 @@ fn ls_sort_by_name_insensitive() { open sample-ls-output.json | sort-by -i name | select name -<<<<<<< HEAD - | to json - "# - )); - - let json_output = r#"[{"name":"a.txt"},{"name":"B.txt"},{"name":"C"}]"#; - -======= | to json --raw "# )); let json_output = r#"[{"name": "B.txt"},{"name": "C"},{"name": "a.txt"}]"#; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.out, json_output); } @@ -151,20 +125,11 @@ fn ls_sort_by_type_name_sensitive() { open sample-ls-output.json | sort-by type name | select name type -<<<<<<< HEAD - | to json - "# - )); - - let json_output = r#"[{"name":"C","type":"Dir"},{"name":"B.txt","type":"File"},{"name":"a.txt","type":"File"}]"#; - -======= | to json --raw "# )); let json_output = r#"[{"name": "C","type": "Dir"},{"name": "a.txt","type": "File"},{"name": "B.txt","type": "File"}]"#; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.out, json_output); } @@ -176,19 +141,10 @@ fn ls_sort_by_type_name_insensitive() { open sample-ls-output.json | sort-by -i type name | select name type -<<<<<<< HEAD - | to json - "# - )); - - let json_output = r#"[{"name":"C","type":"Dir"},{"name":"a.txt","type":"File"},{"name":"B.txt","type":"File"}]"#; - -======= | to json --raw "# )); let json_output = r#"[{"name": "C","type": "Dir"},{"name": "a.txt","type": "File"},{"name": "B.txt","type": "File"}]"#; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.out, json_output); } diff --git a/crates/nu-command/tests/commands/source.rs b/crates/nu-command/tests/commands/source.rs index 0f2263ec7b..dcc342d832 100644 --- a/crates/nu-command/tests/commands/source.rs +++ b/crates/nu-command/tests/commands/source.rs @@ -1,15 +1,7 @@ use nu_test_support::fs::{AbsolutePath, DisplayPath, Stub::FileWithContent}; use nu_test_support::nu; -<<<<<<< HEAD -use nu_test_support::pipeline as input; -use nu_test_support::playground::{says, Playground}; - -use hamcrest2::assert_that; -use hamcrest2::prelude::*; -======= use nu_test_support::pipeline; use nu_test_support::playground::Playground; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[should_panic] #[test] @@ -45,18 +37,6 @@ fn sources_also_files_under_custom_lib_dirs_path() { "#, )]); -<<<<<<< HEAD - assert_that!( - nu.pipeline(&input( - r#" - source my_library.nu ; - - hello - "#, - )), - says().stdout("hello nu") - ); -======= let actual = nu!( cwd: ".", pipeline( r#" @@ -67,7 +47,6 @@ fn sources_also_files_under_custom_lib_dirs_path() { )); assert_eq!(actual.out, "hello nu"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }) } @@ -122,11 +101,8 @@ fn try_source_foo_without_quotes_in(testdir: &str, playdir: &str) { }); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn sources_unicode_file_in_normal_dir() { try_source_foo_with_single_quotes_in("foo", "source_test_1"); @@ -134,11 +110,8 @@ fn sources_unicode_file_in_normal_dir() { try_source_foo_without_quotes_in("foo", "source_test_3"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn sources_unicode_file_in_unicode_dir_without_spaces_1() { try_source_foo_with_single_quotes_in("πŸš’", "source_test_4"); @@ -146,11 +119,8 @@ fn sources_unicode_file_in_unicode_dir_without_spaces_1() { try_source_foo_without_quotes_in("πŸš’", "source_test_6"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[cfg(not(windows))] // ':' is not allowed in Windows paths #[test] fn sources_unicode_file_in_unicode_dir_without_spaces_2() { @@ -159,22 +129,16 @@ fn sources_unicode_file_in_unicode_dir_without_spaces_2() { try_source_foo_without_quotes_in(":fire_engine:", "source_test_9"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn sources_unicode_file_in_unicode_dir_with_spaces_1() { try_source_foo_with_single_quotes_in("e-$ Γ¨Ρ€Ρ‚πŸš’β™žδΈ­η‰‡-j", "source_test_8"); try_source_foo_with_double_quotes_in("e-$ Γ¨Ρ€Ρ‚πŸš’β™žδΈ­η‰‡-j", "source_test_9"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[cfg(not(windows))] // ':' is not allowed in Windows paths #[test] fn sources_unicode_file_in_unicode_dir_with_spaces_2() { diff --git a/crates/nu-command/tests/commands/split_by.rs b/crates/nu-command/tests/commands/split_by.rs index ae767ee5f0..7cfede1a14 100644 --- a/crates/nu-command/tests/commands/split_by.rs +++ b/crates/nu-command/tests/commands/split_by.rs @@ -49,10 +49,6 @@ fn errors_if_no_table_given_as_input() { "# )); -<<<<<<< HEAD - assert!(actual.err.contains("Expected table from pipeline")); -======= assert!(actual.err.contains("requires a table")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }) } diff --git a/crates/nu-command/tests/commands/split_column.rs b/crates/nu-command/tests/commands/split_column.rs new file mode 100644 index 0000000000..cb591e5002 --- /dev/null +++ b/crates/nu-command/tests/commands/split_column.rs @@ -0,0 +1,28 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn to_column() { + Playground::setup("split_column_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "sample.txt", + r#" + importer,shipper,tariff_item,name,origin + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open sample.txt + | lines + | str trim + | split column "," + | get Column2 + "# + )); + + assert!(actual.out.contains("shipper")); + }) +} diff --git a/crates/nu-command/tests/commands/split_row.rs b/crates/nu-command/tests/commands/split_row.rs new file mode 100644 index 0000000000..e7e7dd4f37 --- /dev/null +++ b/crates/nu-command/tests/commands/split_row.rs @@ -0,0 +1,28 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn to_row() { + Playground::setup("split_row_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "sample.txt", + r#" + importer,shipper,tariff_item,name,origin + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open sample.txt + | lines + | str trim + | split row "," + | length + "# + )); + + assert!(actual.out.contains('5')); + }) +} diff --git a/crates/nu-command/tests/commands/str_/collect.rs b/crates/nu-command/tests/commands/str_/collect.rs index a52e4a2166..73db93cf13 100644 --- a/crates/nu-command/tests/commands/str_/collect.rs +++ b/crates/nu-command/tests/commands/str_/collect.rs @@ -44,18 +44,10 @@ fn sum_one_to_four() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - echo 1..4 | into string | str collect "+" | math eval -======= 1..4 | each { $it } | into string | str collect "+" | math eval ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ) ); -<<<<<<< HEAD - assert!(actual.out.contains("10.0")); -======= assert!(actual.out.contains("10")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/commands/str_/into_string.rs b/crates/nu-command/tests/commands/str_/into_string.rs new file mode 100644 index 0000000000..9a50bcd6ac --- /dev/null +++ b/crates/nu-command/tests/commands/str_/into_string.rs @@ -0,0 +1,158 @@ +use nu_test_support::playground::{Dirs, Playground}; +use nu_test_support::{nu, pipeline}; + +#[test] +fn from_range() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo 1..5 | into string | to json + "# + ) + ); + + assert_eq!(actual.out, "[\"1\",\"2\",\"3\",\"4\",\"5\"]"); +} + +#[test] +fn from_number() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo 5 | into string + "# + ) + ); + + assert_eq!(actual.out, "5"); +} + +#[test] +fn from_decimal() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo 1.5 | into string + "# + ) + ); + + assert_eq!(actual.out, "1.5"); +} + +#[test] +fn from_boolean() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo $true | into string + "# + ) + ); + + assert_eq!(actual.out, "true"); +} + +#[test] +fn from_string() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo "one" | into string + "# + ) + ); + + assert_eq!(actual.out, "one"); +} + +#[test] +fn from_filename() { + Playground::setup("from_filename", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "sample.toml", + r#" + [dependency] + name = "nu" + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), + "ls sample.toml | get name | into string" + ); + + assert_eq!(actual.out, "sample.toml"); + }) +} + +#[test] +fn from_filesize() { + Playground::setup("from_filesize", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "sample.toml", + r#" + [dependency] + name = "nu" + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), + "ls sample.toml | get size | into string" + ); + + assert_eq!(actual.out, "25 B"); + }) +} + +#[test] +fn from_decimal_correct_trailing_zeros() { + let actual = nu!( + cwd: ".", pipeline( + r#" + = 1.23000 | into string -d 3 + "# + )); + + assert!(actual.out.contains("1.230")); +} + +#[test] +fn from_int_decimal_correct_trailing_zeros() { + let actual = nu!( + cwd: ".", pipeline( + r#" + = 1.00000 | into string -d 3 + "# + )); + + assert!(actual.out.contains("1.000")); +} + +#[test] +fn from_int_decimal_trim_trailing_zeros() { + let actual = nu!( + cwd: ".", pipeline( + r#" + = 1.00000 | into string | format "{$it} flat" + "# + )); + + assert!(actual.out.contains("1 flat")); // "1" would match "1.0" +} + +#[test] +fn from_table() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo '[{"name": "foo", "weight": 32.377}, {"name": "bar", "weight": 15.2}]' + | from json + | into string weight -d 2 + "# + )); + + assert!(actual.out.contains("32.38")); + assert!(actual.out.contains("15.20")); +} diff --git a/crates/nu-command/tests/commands/str_/mod.rs b/crates/nu-command/tests/commands/str_/mod.rs index 91d12900a2..9f8c23d5fc 100644 --- a/crates/nu-command/tests/commands/str_/mod.rs +++ b/crates/nu-command/tests/commands/str_/mod.rs @@ -29,11 +29,7 @@ fn error_trim_multiple_chars() { let actual = nu!( cwd: ".", pipeline( r#" -<<<<<<< HEAD - echo 'does it work now?!' | str trim -c '?!' -======= echo "does it work now?!" | str trim -c "?!" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ) ); @@ -128,11 +124,7 @@ fn converts_to_int() { r#" echo '{number_as_string: "1"}' | from json -<<<<<<< HEAD - | str to-int number_as_string -======= | into int number_as_string ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | rename number | where number == 1 | get number @@ -150,11 +142,7 @@ fn converts_to_decimal() { r#" echo "3.1, 0.0415" | split row "," -<<<<<<< HEAD - | str to-decimal -======= | into decimal ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | math sum "# )); diff --git a/crates/nu-command/tests/commands/touch.rs b/crates/nu-command/tests/commands/touch.rs new file mode 100644 index 0000000000..affc1d14cc --- /dev/null +++ b/crates/nu-command/tests/commands/touch.rs @@ -0,0 +1,31 @@ +use nu_test_support::nu; +use nu_test_support::playground::Playground; + +#[test] +fn creates_a_file_when_it_doesnt_exist() { + Playground::setup("create_test_1", |dirs, _sandbox| { + nu!( + cwd: dirs.test(), + "touch i_will_be_created.txt" + ); + + let path = dirs.test().join("i_will_be_created.txt"); + assert!(path.exists()); + }) +} + +#[test] +fn creates_two_files() { + Playground::setup("create_test_2", |dirs, _sandbox| { + nu!( + cwd: dirs.test(), + "touch a b" + ); + + let path = dirs.test().join("a"); + assert!(path.exists()); + + let path2 = dirs.test().join("b"); + assert!(path2.exists()); + }) +} diff --git a/crates/nu-command/tests/commands/uniq.rs b/crates/nu-command/tests/commands/uniq.rs index 39035133d1..dd7f433a97 100644 --- a/crates/nu-command/tests/commands/uniq.rs +++ b/crates/nu-command/tests/commands/uniq.rs @@ -61,11 +61,8 @@ fn uniq_values() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn nested_json_structures() { Playground::setup("uniq_test_3", |dirs, sandbox| { @@ -130,22 +127,14 @@ fn nested_json_structures() { }) } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn uniq_when_keys_out_of_order() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo '[{"a": "a", "b": [1,2,3]},{"b": [1,2,3], "a": "a"}]' - | from json -======= [{"a": "a", "b": [1,2,3]}, {"b": [1,2,3], "a": "a"}] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | uniq | length @@ -155,22 +144,14 @@ fn uniq_when_keys_out_of_order() { assert_eq!(actual.out, "1"); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn uniq_counting() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo '["A", "B", "A"]' - | from json -======= ["A", "B", "A"] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | wrap item | uniq --count | where item == A @@ -182,12 +163,7 @@ fn uniq_counting() { let actual = nu!( cwd: "tests/fixtures/formats", pipeline( r#" -<<<<<<< HEAD - echo '["A", "B", "A"]' - | from json -======= echo ["A", "B", "A"] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | wrap item | uniq --count | where item == B diff --git a/crates/nu-command/tests/commands/update.rs b/crates/nu-command/tests/commands/update.rs new file mode 100644 index 0000000000..5506fb4880 --- /dev/null +++ b/crates/nu-command/tests/commands/update.rs @@ -0,0 +1,60 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn sets_the_column() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open cargo_sample.toml + | update dev-dependencies.pretty_assertions "0.7.0" + | get dev-dependencies.pretty_assertions + "# + )); + + assert_eq!(actual.out, "0.7.0"); +} + +#[cfg(features = "inc")] +#[test] +fn sets_the_column_from_a_block_run_output() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open cargo_sample.toml + | update dev-dependencies.pretty_assertions { open cargo_sample.toml | get dev-dependencies.pretty_assertions | inc --minor } + | get dev-dependencies.pretty_assertions + "# + )); + + assert_eq!(actual.out, "0.7.0"); +} + +#[test] +fn sets_the_column_from_a_block_full_stream_output() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + wrap content + | update content { open --raw cargo_sample.toml | lines | first 5 } + | get content.1 + | str contains "nu" + "# + )); + + assert_eq!(actual.out, "true"); +} + +#[test] +fn sets_the_column_from_a_subexpression() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + wrap content + | update content (open --raw cargo_sample.toml | lines | first 5) + | get content.1 + | str contains "nu" + "# + )); + + assert_eq!(actual.out, "true"); +} diff --git a/crates/nu-command/tests/commands/where_.rs b/crates/nu-command/tests/commands/where_.rs new file mode 100644 index 0000000000..c4eb69c639 --- /dev/null +++ b/crates/nu-command/tests/commands/where_.rs @@ -0,0 +1,166 @@ +use nu_test_support::nu; + +#[cfg(feature = "sqlite")] +use nu_test_support::pipeline; + +#[test] +fn filters_by_unit_size_comparison() { + let actual = nu!( + cwd: "tests/fixtures/formats", + "ls | where size > 1kib | sort-by size | get name | first 1 | str trim" + ); + + assert_eq!(actual.out, "cargo_sample.toml"); +} + +#[test] +fn filters_with_nothing_comparison() { + let actual = nu!( + cwd: "tests/fixtures/formats", + r#"echo '[{"foo": 3}, {"foo": null}, {"foo": 4}]' | from json | get foo | compact | where $it > 1 | math sum"# + ); + + assert_eq!(actual.out, "7"); +} + +#[test] +fn where_in_table() { + let actual = nu!( + cwd: "tests/fixtures/formats", + r#"echo '[{"name": "foo", "size": 3}, {"name": "foo", "size": 2}, {"name": "bar", "size": 4}]' | from json | where name in ["foo"] | get size | math sum"# + ); + + assert_eq!(actual.out, "5"); +} + +#[test] +fn where_not_in_table() { + let actual = nu!( + cwd: "tests/fixtures/formats", + r#"echo '[{"name": "foo", "size": 3}, {"name": "foo", "size": 2}, {"name": "bar", "size": 4}]' | from json | where name not-in ["foo"] | get size | math sum"# + ); + + assert_eq!(actual.out, "4"); +} + +#[cfg(feature = "sqlite")] +#[test] +fn explicit_block_condition() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | where table_name == ints + | get table_values + | first 4 + | where {= $it.z > 4200} + | get z + "# + )); + + assert_eq!(actual.out, "4253"); +} + +#[cfg(feature = "sqlite")] +#[test] +fn binary_operator_comparisons() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | where table_name == ints + | get table_values + | first 4 + | where z > 4200 + | get z + "# + )); + + assert_eq!(actual.out, "4253"); + + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | where table_name == ints + | get table_values + | first 4 + | where z >= 4253 + | get z + "# + )); + + assert_eq!(actual.out, "4253"); + + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | where table_name == ints + | get table_values + | first 4 + | where z < 10 + | get z + "# + )); + + assert_eq!(actual.out, "1"); + + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | where table_name == ints + | get table_values + | first 4 + | where z <= 1 + | get z + "# + )); + + assert_eq!(actual.out, "1"); + + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | where table_name == ints + | get table_values + | where z != 1 + | first 1 + | get z + "# + )); + + assert_eq!(actual.out, "42"); +} + +#[cfg(feature = "sqlite")] +#[test] +fn contains_operator() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | where table_name == strings + | get table_values + | where x =~ ell + | length + "# + )); + + assert_eq!(actual.out, "4"); + + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | where table_name == strings + | get table_values + | where x !~ ell + | length + "# + )); + + assert_eq!(actual.out, "2"); +} diff --git a/crates/nu-command/tests/commands/which.rs b/crates/nu-command/tests/commands/which.rs new file mode 100644 index 0000000000..a16e571c52 --- /dev/null +++ b/crates/nu-command/tests/commands/which.rs @@ -0,0 +1,96 @@ +use nu_test_support::nu; + +#[test] +fn which_ls() { + let actual = nu!( + cwd: ".", + "which ls | get path | str trim" + ); + + assert_eq!(actual.out, "Nushell built-in command"); +} + +#[test] +fn which_alias_ls() { + let actual = nu!( + cwd: ".", + "alias ls = ls -a; which ls | get path | str trim" + ); + + assert_eq!(actual.out, "Nushell alias: ls -a"); +} + +#[test] +fn which_def_ls() { + let actual = nu!( + cwd: ".", + "def ls [] {echo def}; which ls | get path | str trim" + ); + + assert_eq!(actual.out, "Nushell custom command"); +} + +#[test] +fn correct_precedence_alias_def_custom() { + let actual = nu!( + cwd: ".", + "def ls [] {echo def}; alias ls = echo alias; which ls | get path | str trim" + ); + + assert_eq!(actual.out, "Nushell alias: echo alias"); +} + +#[test] +fn multiple_reports_for_alias_def_custom() { + let actual = nu!( + cwd: ".", + "def ls [] {echo def}; alias ls = echo alias; which -a ls | length" + ); + + let length: i32 = actual.out.parse().unwrap(); + assert!(length >= 3); +} + +// `get_aliases_with_name` and `get_custom_commands_with_name` don't return the correct count of +// values +// I suspect this is due to the ScopeFrame getting discarded at '}' and the command is then +// executed in the parent scope +// See: parse_definition, line 2187 for reference. +#[ignore] +#[test] +fn multiple_reports_of_multiple_alias() { + let actual = nu!( + cwd: ".", + "alias xaz = echo alias1; def helper [] {alias xaz = echo alias2; which -a xaz}; helper | length" + ); + + let length: i32 = actual.out.parse().unwrap(); + assert_eq!(length, 2); +} + +#[ignore] +#[test] +fn multiple_reports_of_multiple_defs() { + let actual = nu!( + cwd: ".", + "def xaz [] {echo def1}; def helper [] { def xaz [] { echo def2 }; which -a xaz }; helper | length" + ); + + let length: i32 = actual.out.parse().unwrap(); + assert_eq!(length, 2); +} + +//Fails due to ParserScope::add_definition +// frame.custom_commands.insert(name.clone(), block.clone()); +// frame.commands.insert(name, whole_stream_command(block)); +#[ignore] +#[test] +fn def_only_seen_once() { + let actual = nu!( + cwd: ".", + "def xaz [] {echo def1}; which -a xaz | length" + ); + //length is 2. One custom_command (def) one built in ("wrongly" added) + let length: i32 = actual.out.parse().unwrap(); + assert_eq!(length, 1); +} diff --git a/crates/nu-command/tests/commands/with_env.rs b/crates/nu-command/tests/commands/with_env.rs index 6e9bbe8440..4f6480bdb6 100644 --- a/crates/nu-command/tests/commands/with_env.rs +++ b/crates/nu-command/tests/commands/with_env.rs @@ -4,11 +4,7 @@ use nu_test_support::nu; fn with_env_extends_environment() { let actual = nu!( cwd: "tests/fixtures/formats", -<<<<<<< HEAD - "with-env [FOO BARRRR] {echo $nu.env} | get FOO" -======= "with-env [FOO BARRRR] {echo $env} | get FOO" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "BARRRR"); @@ -18,11 +14,7 @@ fn with_env_extends_environment() { fn with_env_shorthand() { let actual = nu!( cwd: "tests/fixtures/formats", -<<<<<<< HEAD - "FOO=BARRRR echo $nu.env | get FOO" -======= "FOO=BARRRR echo $env | get FOO" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "BARRRR"); @@ -42,11 +34,7 @@ fn shorthand_doesnt_reorder_arguments() { fn with_env_shorthand_trims_quotes() { let actual = nu!( cwd: "tests/fixtures/formats", -<<<<<<< HEAD - "FOO='BARRRR' echo $nu.env | get FOO" -======= "FOO='BARRRR' echo $env | get FOO" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "BARRRR"); @@ -56,68 +44,42 @@ fn with_env_shorthand_trims_quotes() { fn with_env_and_shorthand_same_result() { let actual_shorthand = nu!( cwd: "tests/fixtures/formats", -<<<<<<< HEAD - "FOO='BARRRR' echo $nu.env | get FOO" -======= "FOO='BARRRR' echo $env | get FOO" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); let actual_normal = nu!( cwd: "tests/fixtures/formats", -<<<<<<< HEAD - "with-env [FOO BARRRR] {echo $nu.env} | get FOO" -======= "with-env [FOO BARRRR] {echo $env} | get FOO" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual_shorthand.out, actual_normal.out); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn with_env_shorthand_nested_quotes() { let actual = nu!( cwd: "tests/fixtures/formats", -<<<<<<< HEAD - "FOO='-arg \"hello world\"' echo $nu.env | get FOO" -======= "FOO='-arg \"hello world\"' echo $env | get FOO" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "-arg \"hello world\""); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn with_env_hides_variables_in_parent_scope() { let actual = nu!( cwd: "tests/fixtures/formats", r#" let-env FOO = "1" -<<<<<<< HEAD - echo $nu.env.FOO - with-env [FOO $nothing] { - echo $nu.env.FOO - } - echo $nu.env.FOO -======= echo $env.FOO with-env [FOO $nothing] { echo $env.FOO } echo $env.FOO ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -126,26 +88,17 @@ fn with_env_hides_variables_in_parent_scope() { assert!(actual.err.contains("Unknown column")); } -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn with_env_shorthand_can_not_hide_variables() { let actual = nu!( cwd: "tests/fixtures/formats", r#" let-env FOO = "1" -<<<<<<< HEAD - echo $nu.env.FOO - FOO=$nothing echo $nu.env.FOO - echo $nu.env.FOO -======= echo $env.FOO FOO=$nothing echo $env.FOO echo $env.FOO ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); diff --git a/crates/nu-command/tests/commands/wrap.rs b/crates/nu-command/tests/commands/wrap.rs new file mode 100644 index 0000000000..968e5f1256 --- /dev/null +++ b/crates/nu-command/tests/commands/wrap.rs @@ -0,0 +1,61 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn wrap_rows_into_a_row() { + Playground::setup("wrap_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "los_tres_caballeros.txt", + r#" + first_name,last_name + AndrΓ©s,Robalino + Jonathan,Turner + Yehuda,Katz + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open los_tres_caballeros.txt + | from csv + | wrap caballeros + | get caballeros + | nth 0 + | get last_name + "# + )); + + assert_eq!(actual.out, "Robalino"); + }) +} + +#[test] +fn wrap_rows_into_a_table() { + Playground::setup("wrap_test_2", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "los_tres_caballeros.txt", + r#" + first_name,last_name + AndrΓ©s,Robalino + Jonathan,Turner + Yehuda,Katz + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open los_tres_caballeros.txt + | from csv + | get last_name + | wrap caballero + | nth 2 + | get caballero + "# + )); + + assert_eq!(actual.out, "Katz"); + }) +} diff --git a/crates/nu-command/tests/commands/zip.rs b/crates/nu-command/tests/commands/zip.rs index db07a40518..903294dca5 100644 --- a/crates/nu-command/tests/commands/zip.rs +++ b/crates/nu-command/tests/commands/zip.rs @@ -1,14 +1,6 @@ use nu_test_support::fs::Stub::FileWithContent; -<<<<<<< HEAD -use nu_test_support::pipeline as input; -use nu_test_support::playground::{says, Playground}; - -use hamcrest2::assert_that; -use hamcrest2::prelude::*; -======= use nu_test_support::playground::Playground; use nu_test_support::{nu, pipeline}; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce const ZIP_POWERED_TEST_ASSERTION_SCRIPT: &str = r#" def expect [ @@ -34,11 +26,8 @@ def add-commits [n] { } "#; -<<<<<<< HEAD -======= // FIXME: jt: needs more work #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn zips_two_tables() { Playground::setup("zip_test_1", |dirs, nu| { @@ -47,14 +36,9 @@ fn zips_two_tables() { &format!("{}\n", ZIP_POWERED_TEST_ASSERTION_SCRIPT), )]); -<<<<<<< HEAD - assert_that!( - nu.pipeline(&input(&format!( -======= let actual = nu!( cwd: ".", pipeline( &format!( ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce r#" source {} ; @@ -69,36 +53,15 @@ fn zips_two_tables() { expect $actual --to-eq [[name, commits]; [andres, 20] [jt, 30]] "#, dirs.test().join("zip_test.nu").display() -<<<<<<< HEAD - ))), - says().stdout("true") - ); -======= ) )); assert_eq!(actual.out, "true"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }) } #[test] fn zips_two_lists() { -<<<<<<< HEAD - Playground::setup("zip_test_2", |_, nu| { - assert_that!( - nu.pipeline(&input( - r#" - echo [0 2 4 6 8] | zip { [1 3 5 7 9] } - | flatten - | into string - | str collect '-' - "# - )), - says().stdout("0-1-2-3-4-5-6-7-8-9") - ); - }) -======= let actual = nu!( cwd: ".", pipeline( r#" @@ -107,5 +70,4 @@ fn zips_two_lists() { )); assert_eq!(actual.out, "0-1-2-3-4-5-6-7-8-9"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-command/tests/format_conversions/bson.rs b/crates/nu-command/tests/format_conversions/bson.rs new file mode 100644 index 0000000000..cd7969e0f2 --- /dev/null +++ b/crates/nu-command/tests/format_conversions/bson.rs @@ -0,0 +1,17 @@ +#[cfg(feature = "bson")] +#[test] +fn table_to_bson_and_back_into_table() { + use nu_test_support::{nu, pipeline}; + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.bson + | to bson + | from bson + | get root + | get 1.b + "# + )); + + assert_eq!(actual.out, "whel"); +} diff --git a/crates/nu-command/tests/format_conversions/csv.rs b/crates/nu-command/tests/format_conversions/csv.rs index 86186cdb30..4839e327ed 100644 --- a/crates/nu-command/tests/format_conversions/csv.rs +++ b/crates/nu-command/tests/format_conversions/csv.rs @@ -34,11 +34,7 @@ fn table_to_csv_text() { | last 1 | to csv | lines -<<<<<<< HEAD - | nth 1 -======= | get 1 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -149,11 +145,7 @@ fn from_csv_text_with_separator_to_table() { cwd: dirs.test(), pipeline( r#" open los_tres_caballeros.txt -<<<<<<< HEAD - | from csv --separator ';' -======= | from csv --separator ";" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | get rusty_luck | length "# @@ -180,11 +172,7 @@ fn from_csv_text_with_tab_separator_to_table() { cwd: dirs.test(), pipeline( r#" open los_tres_caballeros.txt -<<<<<<< HEAD - | from csv --separator '\t' -======= | from csv --separator (char tab) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | get rusty_luck | length "# diff --git a/crates/nu-command/tests/format_conversions/eml.rs b/crates/nu-command/tests/format_conversions/eml.rs new file mode 100644 index 0000000000..41acb13cb9 --- /dev/null +++ b/crates/nu-command/tests/format_conversions/eml.rs @@ -0,0 +1,93 @@ +use nu_test_support::{nu, pipeline}; + +const TEST_CWD: &str = "tests/fixtures/formats"; + +// The To field in this email is just "to@example.com", which gets parsed out as the Address. The Name is empty. +#[test] +fn from_eml_get_to_field() { + let actual = nu!( + cwd: TEST_CWD, + pipeline( + r#" + open sample.eml + | get To + | get Address + "# + ) + ); + + assert_eq!(actual.out, "to@example.com"); + + let actual = nu!( + cwd: TEST_CWD, + pipeline( + r#" + open sample.eml + | get To + | get Name + "# + ) + ); + + assert_eq!(actual.out, ""); +} + +// The Reply-To field in this email is "replyto@example.com" , meaning both the Name and Address values are identical. +#[test] +fn from_eml_get_replyto_field() { + let actual = nu!( + cwd: TEST_CWD, + pipeline( + r#" + open sample.eml + | get Reply-To + | get Address + "# + ) + ); + + assert_eq!(actual.out, "replyto@example.com"); + + let actual = nu!( + cwd: TEST_CWD, + pipeline( + r#" + open sample.eml + | get Reply-To + | get Name + "# + ) + ); + + assert_eq!(actual.out, "replyto@example.com"); +} + +#[test] +fn from_eml_get_subject_field() { + let actual = nu!( + cwd: TEST_CWD, + pipeline( + r#" + open sample.eml + | get Subject + "# + ) + ); + + assert_eq!(actual.out, "Test Message"); +} + +#[test] +fn from_eml_get_another_header_field() { + let actual = nu!( + cwd: TEST_CWD, + pipeline( + r#" + open sample.eml + | get MIME-Version + "# + ) + ); + + assert_eq!(actual.out, "1.0"); +} diff --git a/crates/nu-command/tests/format_conversions/html.rs b/crates/nu-command/tests/format_conversions/html.rs index 08de6aba47..555ac1abb3 100644 --- a/crates/nu-command/tests/format_conversions/html.rs +++ b/crates/nu-command/tests/format_conversions/html.rs @@ -56,11 +56,7 @@ fn test_cd_html_color_flag_dark_false() { ); assert_eq!( actual.out, -<<<<<<< HEAD - r"Change to a new path.

Usage:
> cd (directory) {flags}

Parameters:
(directory) the directory to change to

Flags:
-h, --help: Display this help message

Examples:
Change to a new directory called 'dirname'
> cd dirname

Change to your home directory
>
cd

Change to your home directory (alternate version)
>
cd
~

Change to the previous directory
>
cd
-

" -======= r"Usage:
> cd (path)

Flags:
-h, --help
Display this help message

Parameters:
(optional) path: the path to change to

" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); } @@ -75,11 +71,7 @@ fn test_no_color_flag() { ); assert_eq!( actual.out, -<<<<<<< HEAD - r"Change to a new path.

Usage:
> cd (directory) {flags}

Parameters:
(directory) the directory to change to

Flags:
-h, --help: Display this help message

Examples:
Change to a new directory called 'dirname'
> cd dirname

Change to your home directory
> cd

Change to your home directory (alternate version)
> cd ~

Change to the previous directory
> cd -

" -======= r"Usage:
> cd (path)

Flags:
-h, --help
Display this help message

Parameters:
(optional) path: the path to change to

" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); } @@ -94,10 +86,6 @@ fn test_html_color_where_flag_dark_false() { ); assert_eq!( actual.out, -<<<<<<< HEAD - r"Filter table to match the condition.

Usage:
> where <condition> {flags}

Parameters:
<condition> the condition that must match

Flags:
-h, --help: Display this help message

Examples:
List all files in the current directory with sizes greater than 2kb
> ls | where size > 2kb

List only the files in the current directory
>
ls
| where type == File

List all files with names that contain "Car"
>
ls
| where name =~ "Car"

List all files that were modified in the last two weeks
>
ls
| where modified <= 2wk

" -======= r"Usage:
> where <cond>

Flags:
-h, --help
Display this help message

Parameters:
cond: condition

" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); } diff --git a/crates/nu-command/tests/format_conversions/ics.rs b/crates/nu-command/tests/format_conversions/ics.rs index 37b876dfa0..ccaa6318cf 100644 --- a/crates/nu-command/tests/format_conversions/ics.rs +++ b/crates/nu-command/tests/format_conversions/ics.rs @@ -47,11 +47,7 @@ fn infers_types() { cwd: dirs.test(), pipeline( r#" open calendar.ics -<<<<<<< HEAD - | get events -======= | get events.0 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | length "# )); @@ -90,13 +86,8 @@ fn from_ics_text_to_table() { r#" open calendar.txt | from ics -<<<<<<< HEAD - | get events - | get properties -======= | get events.0 | get properties.0 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | where name == "SUMMARY" | first | get value diff --git a/crates/nu-command/tests/format_conversions/json.rs b/crates/nu-command/tests/format_conversions/json.rs new file mode 100644 index 0000000000..1cb059c148 --- /dev/null +++ b/crates/nu-command/tests/format_conversions/json.rs @@ -0,0 +1,100 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn table_to_json_text_and_from_json_text_back_into_table() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sgml_description.json + | to json + | from json + | get glossary.GlossDiv.GlossList.GlossEntry.GlossSee + "# + )); + + assert_eq!(actual.out, "markup"); +} + +#[test] +fn from_json_text_to_table() { + Playground::setup("filter_from_json_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "katz.txt", + r#" + { + "katz": [ + {"name": "Yehuda", "rusty_luck": 1}, + {"name": "Jonathan", "rusty_luck": 1}, + {"name": "Andres", "rusty_luck": 1}, + {"name":"GorbyPuff", "rusty_luck": 1} + ] + } + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), + "open katz.txt | from json | get katz | get rusty_luck | length " + ); + + assert_eq!(actual.out, "4"); + }) +} + +#[test] +fn from_json_text_recognizing_objects_independently_to_table() { + Playground::setup("filter_from_json_test_2", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "katz.txt", + r#" + {"name": "Yehuda", "rusty_luck": 1} + {"name": "Jonathan", "rusty_luck": 1} + {"name": "Andres", "rusty_luck": 1} + {"name":"GorbyPuff", "rusty_luck": 3} + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open katz.txt + | from json -o + | where name == "GorbyPuff" + | get rusty_luck + "# + )); + + assert_eq!(actual.out, "3"); + }) +} + +#[test] +fn table_to_json_text() { + Playground::setup("filter_to_json_test", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "sample.txt", + r#" + JonAndrehudaTZ,3 + GorbyPuff,100 + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open sample.txt + | lines + | split column "," name luck + | select name + | to json + | from json + | nth 0 + | get name + "# + )); + + assert_eq!(actual.out, "JonAndrehudaTZ"); + }) +} diff --git a/crates/nu-command/tests/format_conversions/markdown.rs b/crates/nu-command/tests/format_conversions/markdown.rs new file mode 100644 index 0000000000..15aef32756 --- /dev/null +++ b/crates/nu-command/tests/format_conversions/markdown.rs @@ -0,0 +1,98 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn md_empty() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo [[]; []] | from json | to md + "# + )); + + assert_eq!(actual.out, ""); +} + +#[test] +fn md_empty_pretty() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo "{}" | from json | to md -p + "# + )); + + assert_eq!(actual.out, ""); +} + +#[test] +fn md_simple() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo 3 | to md + "# + )); + + assert_eq!(actual.out, "3"); +} + +#[test] +fn md_simple_pretty() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo 3 | to md -p + "# + )); + + assert_eq!(actual.out, "3"); +} + +#[test] +fn md_table() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo [[name]; [jason]] | to md + "# + )); + + assert_eq!(actual.out, "|name||-||jason|"); +} + +#[test] +fn md_table_pretty() { + let actual = nu!( + cwd: ".", pipeline( + r#" + echo [[name]; [joseph]] | to md -p + "# + )); + + assert_eq!(actual.out, "| name || ------ || joseph |"); +} + +#[test] +fn md_combined() { + let actual = nu!( + cwd: ".", pipeline( + r#" + def title [] { + echo [[H1]; ["Nu top meals"]] + }; + + def meals [] { + echo [[dish]; [Arepa] [Taco] [Pizza]] + }; + + title + | append (meals) + | to md --per-element --pretty + "# + )); + + assert_eq!( + actual.out, + "# Nu top meals| dish || ----- || Arepa || Taco || Pizza |" + ); +} diff --git a/crates/nu-command/tests/format_conversions/mod.rs b/crates/nu-command/tests/format_conversions/mod.rs new file mode 100644 index 0000000000..5af12f9fc1 --- /dev/null +++ b/crates/nu-command/tests/format_conversions/mod.rs @@ -0,0 +1,17 @@ +mod bson; +mod csv; +mod eml; +mod html; +mod ics; +mod json; +mod markdown; +mod ods; +mod sqlite; +mod ssv; +mod toml; +mod tsv; +mod url; +mod vcf; +mod xlsx; +mod xml; +mod yaml; diff --git a/crates/nu-command/tests/format_conversions/ods.rs b/crates/nu-command/tests/format_conversions/ods.rs index 1a90911e08..c322e914e6 100644 --- a/crates/nu-command/tests/format_conversions/ods.rs +++ b/crates/nu-command/tests/format_conversions/ods.rs @@ -22,12 +22,8 @@ fn from_ods_file_to_table_select_sheet() { r#" open sample_data.ods --raw | from ods -s ["SalesOrders"] -<<<<<<< HEAD - | get -======= | columns | get 0 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); diff --git a/crates/nu-command/tests/format_conversions/sqlite.rs b/crates/nu-command/tests/format_conversions/sqlite.rs new file mode 100644 index 0000000000..de6ce8ccfa --- /dev/null +++ b/crates/nu-command/tests/format_conversions/sqlite.rs @@ -0,0 +1,36 @@ +#[cfg(feature = "sqlite")] +use nu_test_support::{nu, pipeline}; + +#[cfg(feature = "sqlite")] +#[test] +fn table_to_sqlite_and_back_into_table() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | to sqlite + | from sqlite + | get table_values + | nth 2 + | get x + "# + )); + + assert_eq!(actual.out, "hello"); +} + +#[cfg(feature = "sqlite")] +#[test] +fn table_to_sqlite_and_back_into_table_select_table() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.db + | to sqlite + | from sqlite -t [strings] + | get table_names + "# + )); + + assert_eq!(actual.out, "strings"); +} diff --git a/crates/nu-command/tests/format_conversions/ssv.rs b/crates/nu-command/tests/format_conversions/ssv.rs new file mode 100644 index 0000000000..76d7045782 --- /dev/null +++ b/crates/nu-command/tests/format_conversions/ssv.rs @@ -0,0 +1,95 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn from_ssv_text_to_table() { + Playground::setup("filter_from_ssv_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "oc_get_svc.txt", + r#" + NAME LABELS SELECTOR IP PORT(S) + docker-registry docker-registry=default docker-registry=default 172.30.78.158 5000/TCP + kubernetes component=apiserver,provider=kubernetes 172.30.0.2 443/TCP + kubernetes-ro component=apiserver,provider=kubernetes 172.30.0.1 80/TCP + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open oc_get_svc.txt + | from ssv + | nth 0 + | get IP + "# + )); + + assert_eq!(actual.out, "172.30.78.158"); + }) +} + +#[test] +fn from_ssv_text_to_table_with_separator_specified() { + Playground::setup("filter_from_ssv_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "oc_get_svc.txt", + r#" + NAME LABELS SELECTOR IP PORT(S) + docker-registry docker-registry=default docker-registry=default 172.30.78.158 5000/TCP + kubernetes component=apiserver,provider=kubernetes 172.30.0.2 443/TCP + kubernetes-ro component=apiserver,provider=kubernetes 172.30.0.1 80/TCP + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open oc_get_svc.txt + | from ssv --minimum-spaces 3 + | nth 0 + | get IP + "# + )); + + assert_eq!(actual.out, "172.30.78.158"); + }) +} + +#[test] +fn from_ssv_text_treating_first_line_as_data_with_flag() { + Playground::setup("filter_from_ssv_test_2", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "oc_get_svc.txt", + r#" + docker-registry docker-registry=default docker-registry=default 172.30.78.158 5000/TCP + kubernetes component=apiserver,provider=kubernetes 172.30.0.2 443/TCP + kubernetes-ro component=apiserver,provider=kubernetes 172.30.0.1 80/TCP + "#, + )]); + + let aligned_columns = nu!( + cwd: dirs.test(), pipeline( + r#" + open oc_get_svc.txt + | from ssv --noheaders -a + | first + | get Column1 + "# + )); + + let separator_based = nu!( + cwd: dirs.test(), pipeline( + r#" + open oc_get_svc.txt + | from ssv --noheaders + | first + | get Column1 + + "# + )); + + assert_eq!(aligned_columns.out, separator_based.out); + assert_eq!(separator_based.out, "docker-registry"); + }) +} diff --git a/crates/nu-command/tests/format_conversions/toml.rs b/crates/nu-command/tests/format_conversions/toml.rs new file mode 100644 index 0000000000..cffeed1c24 --- /dev/null +++ b/crates/nu-command/tests/format_conversions/toml.rs @@ -0,0 +1,16 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn table_to_toml_text_and_from_toml_text_back_into_table() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open cargo_sample.toml + | to toml + | from toml + | get package.name + "# + )); + + assert_eq!(actual.out, "nu"); +} diff --git a/crates/nu-command/tests/format_conversions/tsv.rs b/crates/nu-command/tests/format_conversions/tsv.rs new file mode 100644 index 0000000000..066fa16ad3 --- /dev/null +++ b/crates/nu-command/tests/format_conversions/tsv.rs @@ -0,0 +1,132 @@ +use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; +use nu_test_support::playground::Playground; +use nu_test_support::{nu, pipeline}; + +#[test] +fn table_to_tsv_text_and_from_tsv_text_back_into_table() { + let actual = nu!( + cwd: "tests/fixtures/formats", + "open caco3_plastics.tsv | to tsv | from tsv | first 1 | get origin" + ); + + assert_eq!(actual.out, "SPAIN"); +} + +#[test] +fn table_to_tsv_text_and_from_tsv_text_back_into_table_using_csv_separator() { + let actual = nu!( + cwd: "tests/fixtures/formats", + r"open caco3_plastics.tsv | to tsv | from csv --separator '\t' | first 1 | get origin" + ); + + assert_eq!(actual.out, "SPAIN"); +} + +#[test] +fn table_to_tsv_text() { + Playground::setup("filter_to_tsv_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "tsv_text_sample.txt", + r#" + importer shipper tariff_item name origin + Plasticos Rival Reverte 2509000000 Calcium carbonate Spain + Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open tsv_text_sample.txt + | lines + | split column "\t" a b c d origin + | last 1 + | to tsv + | lines + | nth 1 + "# + )); + + assert!(actual.out.contains("Colombia")); + }) +} + +#[test] +fn table_to_tsv_text_skipping_headers_after_conversion() { + Playground::setup("filter_to_tsv_test_2", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "tsv_text_sample.txt", + r#" + importer shipper tariff_item name origin + Plasticos Rival Reverte 2509000000 Calcium carbonate Spain + Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open tsv_text_sample.txt + | lines + | split column "\t" a b c d origin + | last 1 + | to tsv --noheaders + "# + )); + + assert!(actual.out.contains("Colombia")); + }) +} + +#[test] +fn from_tsv_text_to_table() { + Playground::setup("filter_from_tsv_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "los_tres_amigos.txt", + r#" + first Name Last Name rusty_luck + AndrΓ©s Robalino 1 + Jonathan Turner 1 + Yehuda Katz 1 + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open los_tres_amigos.txt + | from tsv + | get rusty_luck + | length + "# + )); + + assert_eq!(actual.out, "3"); + }) +} + +#[test] +fn from_tsv_text_skipping_headers_to_table() { + Playground::setup("filter_from_tsv_test_2", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContentToBeTrimmed( + "los_tres_amigos.txt", + r#" + AndrΓ©s Robalino 1 + Jonathan Turner 1 + Yehuda Katz 1 + "#, + )]); + + let actual = nu!( + cwd: dirs.test(), pipeline( + r#" + open los_tres_amigos.txt + | from tsv --noheaders + | get Column3 + | length + "# + )); + + assert_eq!(actual.out, "3"); + }) +} diff --git a/crates/nu-command/tests/format_conversions/url.rs b/crates/nu-command/tests/format_conversions/url.rs new file mode 100644 index 0000000000..2187fa3822 --- /dev/null +++ b/crates/nu-command/tests/format_conversions/url.rs @@ -0,0 +1,16 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn can_encode_and_decode_urlencoding() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open sample.url + | to url + | from url + | get cheese + "# + )); + + assert_eq!(actual.out, "comtΓ©"); +} diff --git a/crates/nu-command/tests/format_conversions/vcf.rs b/crates/nu-command/tests/format_conversions/vcf.rs index 5626181042..ee4bf1bb52 100644 --- a/crates/nu-command/tests/format_conversions/vcf.rs +++ b/crates/nu-command/tests/format_conversions/vcf.rs @@ -70,11 +70,7 @@ fn from_vcf_text_to_table() { r#" open contacts.txt | from vcf -<<<<<<< HEAD - | get properties -======= | get properties.0 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | where name == "EMAIL" | first | get value diff --git a/crates/nu-command/tests/format_conversions/xlsx.rs b/crates/nu-command/tests/format_conversions/xlsx.rs index 9767475ef5..961c305cae 100644 --- a/crates/nu-command/tests/format_conversions/xlsx.rs +++ b/crates/nu-command/tests/format_conversions/xlsx.rs @@ -22,12 +22,8 @@ fn from_excel_file_to_table_select_sheet() { r#" open sample_data.xlsx --raw | from xlsx -s ["SalesOrders"] -<<<<<<< HEAD - | get -======= | columns | get 0 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); diff --git a/crates/nu-command/tests/format_conversions/xml.rs b/crates/nu-command/tests/format_conversions/xml.rs index 6b321f96ce..15a62d6907 100644 --- a/crates/nu-command/tests/format_conversions/xml.rs +++ b/crates/nu-command/tests/format_conversions/xml.rs @@ -8,11 +8,7 @@ fn table_to_xml_text_and_from_xml_text_back_into_table() { open jonathan.xml | to xml | from xml -<<<<<<< HEAD - | get rss.children.channel.children.0.item.children.0.guid.attributes.isPermaLink -======= | get rss.children.channel.children.0.3.item.children.guid.4.attributes.isPermaLink ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); diff --git a/crates/nu-command/tests/format_conversions/yaml.rs b/crates/nu-command/tests/format_conversions/yaml.rs new file mode 100644 index 0000000000..887256637c --- /dev/null +++ b/crates/nu-command/tests/format_conversions/yaml.rs @@ -0,0 +1,16 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn table_to_yaml_text_and_from_yaml_text_back_into_table() { + let actual = nu!( + cwd: "tests/fixtures/formats", pipeline( + r#" + open appveyor.yml + | to yaml + | from yaml + | get environment.global.PROJECT_NAME + "# + )); + + assert_eq!(actual.out, "nushell"); +} diff --git a/crates/nu-command/tests/main.rs b/crates/nu-command/tests/main.rs index 5ed0c22d23..62f9eb37d2 100644 --- a/crates/nu-command/tests/main.rs +++ b/crates/nu-command/tests/main.rs @@ -1,25 +1,10 @@ -<<<<<<< HEAD -======= use nu_command::create_default_context; use nu_protocol::engine::StateWorkingSet; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use quickcheck_macros::quickcheck; mod commands; mod format_conversions; -<<<<<<< HEAD -use nu_engine::EvaluationContext; - -#[quickcheck] -fn quickcheck_parse(data: String) -> bool { - let (tokens, err) = nu_parser::lex(&data, 0, nu_parser::NewlineMode::Normal); - let (lite_block, err2) = nu_parser::parse_block(tokens); - - if err.is_none() && err2.is_none() { - let context = EvaluationContext::basic(); - let _ = nu_parser::classify_block(&lite_block, &context.scope); -======= // use nu_engine::EvaluationContext; #[quickcheck] @@ -36,7 +21,6 @@ fn quickcheck_parse(data: String) -> bool { let _ = nu_parser::parse_block(&mut working_set, &lite_block, false); } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } true } diff --git a/crates/nu-engine/Cargo.toml b/crates/nu-engine/Cargo.toml index 1cc0f534c9..17306beb45 100644 --- a/crates/nu-engine/Cargo.toml +++ b/crates/nu-engine/Cargo.toml @@ -1,75 +1,14 @@ [package] -<<<<<<< HEAD -authors = ["The Nu Project Contributors"] -description = "Core commands for nushell" -edition = "2018" -license = "MIT" name = "nu-engine" -version = "0.43.0" - -[dependencies] -nu-data = { version = "0.43.0", path="../nu-data" } -nu-errors = { version = "0.43.0", path="../nu-errors" } -nu-parser = { version = "0.43.0", path="../nu-parser" } -nu-plugin = { version = "0.43.0", path="../nu-plugin" } -nu-protocol = { version = "0.43.0", path="../nu-protocol" } -nu-source = { version = "0.43.0", path="../nu-source" } -nu-stream = { version = "0.43.0", path="../nu-stream" } -nu-value-ext = { version = "0.43.0", path="../nu-value-ext" } -nu-ansi-term = { version = "0.43.0", path="../nu-ansi-term" } -nu-test-support = { version = "0.43.0", path="../nu-test-support" } -nu-path = { version = "0.43.0", path="../nu-path" } - -trash = { version = "2.0.2", optional = true } -which = { version="4.0.2", optional=true } -codespan-reporting = "0.11.0" -bigdecimal = { package = "bigdecimal", version = "0.3.0", features = ["serde"] } -bytes = "1.1.0" -chrono = { version="0.4.19", features=["serde"] } -derive-new = "0.5.8" -dirs-next = "2.0.0" -encoding_rs = "0.8.28" -filesize = "0.2.0" -fs_extra = "1.2.0" -getset = "0.1.1" -glob = "0.3.0" -indexmap = { version="1.6.1", features=["serde-1"] } -itertools = "0.10.0" -lazy_static = "1.*" -log = "0.4.14" -num-bigint = { version="0.4.3", features=["serde"] } -parking_lot = "0.11.1" -rayon = "1.5.0" -serde = { version="1.0.123", features=["derive"] } -serde_json = "1.0.61" -tempfile = "3.2.0" -term_size = "0.3.2" -termcolor = "1.1.2" - -[target.'cfg(unix)'.dependencies] -umask = "1.0.0" -users = "0.11.0" - -[dev-dependencies] -nu-test-support = { version = "0.43.0", path="../nu-test-support" } -hamcrest2 = "0.3.0" - -[features] -rustyline-support = [] -trash-support = ["trash"] -dataframe = ["nu-protocol/dataframe"] -======= -name = "nu-engine" -version = "0.1.0" +version = "0.59.0" edition = "2021" [dependencies] -nu-protocol = { path = "../nu-protocol", features = ["plugin"] } -nu-path = { path = "../nu-path" } +nu-protocol = { path = "../nu-protocol", features = ["plugin"], version = "0.59.0" } +nu-path = { path = "../nu-path", version = "0.59.0" } itertools = "0.10.1" chrono = { version="0.4.19", features=["serde"] } glob = "0.3.0" [features] plugin = [] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-engine/src/documentation.rs b/crates/nu-engine/src/documentation.rs index e4cc735665..adadc7f1b3 100644 --- a/crates/nu-engine/src/documentation.rs +++ b/crates/nu-engine/src/documentation.rs @@ -1,18 +1,9 @@ -<<<<<<< HEAD -use crate::evaluate::scope::Scope; -use crate::whole_stream_command::WholeStreamCommand; -use indexmap::IndexMap; -use itertools::Itertools; -use nu_protocol::{NamedType, PositionalType, Signature, UntaggedValue, Value}; -use nu_source::PrettyDebug; -======= use itertools::Itertools; use nu_protocol::{ ast::Call, engine::{EngineState, Stack}, Example, IntoPipelineData, Signature, Span, Value, }; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use std::collections::HashMap; const COMMANDS_DOCS_DIR: &str = "docs/commands"; @@ -20,41 +11,12 @@ const COMMANDS_DOCS_DIR: &str = "docs/commands"; #[derive(Default)] pub struct DocumentationConfig { no_subcommands: bool, -<<<<<<< HEAD -======= //FIXME: add back in color support #[allow(dead_code)] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce no_color: bool, brief: bool, } -<<<<<<< HEAD -fn generate_doc(name: &str, scope: &Scope) -> IndexMap { - let mut row_entries = IndexMap::new(); - let command = scope - .get_command(name) - .unwrap_or_else(|| panic!("Expected command '{}' from names to be in registry", name)); - row_entries.insert( - "name".to_owned(), - UntaggedValue::string(name).into_untagged_value(), - ); - row_entries.insert( - "usage".to_owned(), - UntaggedValue::string(command.usage()).into_untagged_value(), - ); - retrieve_doc_link(name).and_then(|link| { - row_entries.insert( - "doc_link".to_owned(), - UntaggedValue::string(link).into_untagged_value(), - ) - }); - row_entries.insert( - "documentation".to_owned(), - UntaggedValue::string(get_documentation( - command.stream_command(), - scope, -======= fn generate_doc( name: &str, engine_state: &EngineState, @@ -96,39 +58,11 @@ fn generate_doc( &command.examples(), engine_state, stack, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce &DocumentationConfig { no_subcommands: true, no_color: true, brief: false, }, -<<<<<<< HEAD - )) - .into_untagged_value(), - ); - row_entries -} - -// generate_docs gets the documentation from each command and returns a Table as output -pub fn generate_docs(scope: &Scope) -> Value { - let mut sorted_names = scope.get_command_names(); - sorted_names.sort(); - - // cmap will map parent commands to it's subcommands e.g. to -> [to csv, to yaml, to bson] - let mut cmap: HashMap> = HashMap::new(); - for name in &sorted_names { - if name.contains(' ') { - let split_name = name.split_whitespace().collect_vec(); - let parent_name = split_name.first().expect("Expected a parent command name"); - if cmap.contains_key(*parent_name) { - let sub_names = cmap - .get_mut(*parent_name) - .expect("Expected an entry for parent"); - sub_names.push(name.to_owned()); - } - } else { - cmap.insert(name.to_owned(), Vec::new()); -======= ), span: head, }); @@ -154,36 +88,11 @@ pub fn generate_docs(engine_state: &EngineState, stack: &mut Stack, head: Span) } } else { cmap.insert(sig.name.to_owned(), Vec::new()); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }; } // Return documentation for each command // Sub-commands are nested under their respective parent commands let mut table = Vec::new(); -<<<<<<< HEAD - for name in &sorted_names { - // Must be a sub-command, skip since it's being handled underneath when we hit the parent command - if !cmap.contains_key(name) { - continue; - } - let mut row_entries = generate_doc(name, scope); - // Iterate over all the subcommands of the parent command - let mut sub_table = Vec::new(); - for sub_name in cmap.get(name).unwrap_or(&Vec::new()) { - let sub_row = generate_doc(sub_name, scope); - sub_table.push(UntaggedValue::row(sub_row).into_untagged_value()); - } - - if !sub_table.is_empty() { - row_entries.insert( - "subcommands".to_owned(), - UntaggedValue::table(&sub_table).into_untagged_value(), - ); - } - table.push(UntaggedValue::row(row_entries).into_untagged_value()); - } - UntaggedValue::table(&table).into_untagged_value() -======= for sig in &signatures { // Must be a sub-command, skip since it's being handled underneath when we hit the parent command if !cmap.contains_key(&sig.name) { @@ -218,7 +127,6 @@ pub fn generate_docs(engine_state: &EngineState, stack: &mut Stack, head: Span) vals: table, span: head, } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } fn retrieve_doc_link(name: &str) -> Option { @@ -238,17 +146,6 @@ fn retrieve_doc_link(name: &str) -> Option { #[allow(clippy::cognitive_complexity)] pub fn get_documentation( -<<<<<<< HEAD - cmd: &dyn WholeStreamCommand, - scope: &Scope, - config: &DocumentationConfig, -) -> String { - let cmd_name = cmd.name(); - let signature = cmd.signature(); - let mut long_desc = String::new(); - - let usage = &cmd.usage(); -======= sig: &Signature, examples: &[Example], engine_state: &EngineState, @@ -259,17 +156,12 @@ pub fn get_documentation( let mut long_desc = String::new(); let usage = &sig.usage; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce if !usage.is_empty() { long_desc.push_str(usage); long_desc.push_str("\n\n"); } -<<<<<<< HEAD - let extra_usage = if config.brief { "" } else { &cmd.extra_usage() }; -======= let extra_usage = if config.brief { "" } else { &sig.extra_usage }; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce if !extra_usage.is_empty() { long_desc.push_str(extra_usage); long_desc.push_str("\n\n"); @@ -277,54 +169,15 @@ pub fn get_documentation( let mut subcommands = vec![]; if !config.no_subcommands { -<<<<<<< HEAD - for name in scope.get_command_names() { - if name.starts_with(&format!("{} ", cmd_name)) { - let subcommand = scope.get_command(&name).expect("This shouldn't happen"); - - subcommands.push(format!(" {} - {}", name, subcommand.usage())); -======= let signatures = engine_state.get_signatures(true); for sig in signatures { if sig.name.starts_with(&format!("{} ", cmd_name)) { subcommands.push(format!(" {} - {}", sig.name, sig.usage)); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } } -<<<<<<< HEAD - let mut one_liner = String::new(); - one_liner.push_str(&signature.name); - one_liner.push(' '); - - for positional in &signature.positional { - match &positional.0 { - PositionalType::Mandatory(name, _m) => { - one_liner.push_str(&format!("<{}> ", name)); - } - PositionalType::Optional(name, _o) => { - one_liner.push_str(&format!("({}) ", name)); - } - } - } - - if signature.rest_positional.is_some() { - one_liner.push_str("...args "); - } - - if !subcommands.is_empty() { - one_liner.push_str(" "); - } - - if !signature.named.is_empty() { - one_liner.push_str("{flags} "); - } - - long_desc.push_str(&format!("Usage:\n > {}\n", one_liner)); -======= long_desc.push_str(&format!("Usage:\n > {}\n", sig.call_signature())); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce if !subcommands.is_empty() { long_desc.push_str("\nSubcommands:\n"); @@ -333,34 +186,6 @@ pub fn get_documentation( long_desc.push('\n'); } -<<<<<<< HEAD - if !signature.positional.is_empty() || signature.rest_positional.is_some() { - long_desc.push_str("\nParameters:\n"); - for positional in &signature.positional { - match &positional.0 { - PositionalType::Mandatory(name, _m) => { - long_desc.push_str(&format!(" <{}> {}\n", name, positional.1)); - } - PositionalType::Optional(name, _o) => { - long_desc.push_str(&format!(" ({}) {}\n", name, positional.1)); - } - } - } - - if let Some(rest_positional) = &signature.rest_positional { - long_desc.push_str(&format!(" ...args: {}\n", rest_positional.2)); - } - } - if !signature.named.is_empty() { - long_desc.push_str(&get_flags_section(&signature)) - } - - let palette = crate::shell::palette::DefaultPalette {}; - let examples = cmd.examples(); - if !examples.is_empty() { - long_desc.push_str("\nExamples:"); - } -======= if !sig.named.is_empty() { long_desc.push_str(&get_flags_section(sig)) } @@ -392,7 +217,6 @@ pub fn get_documentation( long_desc.push_str("\nExamples:"); } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce for example in examples { long_desc.push('\n'); long_desc.push_str(" "); @@ -400,12 +224,6 @@ pub fn get_documentation( if config.no_color { long_desc.push_str(&format!("\n > {}\n", example.example)); -<<<<<<< HEAD - } else { - let colored_example = - crate::shell::painter::Painter::paint_string(example.example, scope, &palette); - long_desc.push_str(&format!("\n > {}\n", colored_example)); -======= } else if let Some(highlighter) = engine_state.find_decl(b"nu-highlight") { let decl = engine_state.get_decl(highlighter); @@ -436,7 +254,6 @@ pub fn get_documentation( } } else { long_desc.push_str(&format!("\n > {}\n", example.example)); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } @@ -445,71 +262,6 @@ pub fn get_documentation( long_desc } -<<<<<<< HEAD -fn get_flags_section(signature: &Signature) -> String { - let mut long_desc = String::new(); - long_desc.push_str("\nFlags:\n"); - for (flag, ty) in &signature.named { - let msg = match ty.0 { - NamedType::Switch(s) => { - if let Some(c) = s { - format!( - " -{}, --{}{} {}\n", - c, - flag, - if !ty.1.is_empty() { ":" } else { "" }, - ty.1 - ) - } else { - format!( - " --{}{} {}\n", - flag, - if !ty.1.is_empty() { ":" } else { "" }, - ty.1 - ) - } - } - NamedType::Mandatory(s, m) => { - if let Some(c) = s { - format!( - " -{}, --{} <{}> (required parameter){} {}\n", - c, - flag, - m.display(), - if !ty.1.is_empty() { ":" } else { "" }, - ty.1 - ) - } else { - format!( - " --{} <{}> (required parameter){} {}\n", - flag, - m.display(), - if !ty.1.is_empty() { ":" } else { "" }, - ty.1 - ) - } - } - NamedType::Optional(s, o) => { - if let Some(c) = s { - format!( - " -{}, --{} <{}>{} {}\n", - c, - flag, - o.display(), - if !ty.1.is_empty() { ":" } else { "" }, - ty.1 - ) - } else { - format!( - " --{} <{}>{} {}\n", - flag, - o.display(), - if !ty.1.is_empty() { ":" } else { "" }, - ty.1 - ) - } - } -======= pub fn get_flags_section(signature: &Signature) -> String { let mut long_desc = String::new(); long_desc.push_str("\nFlags:\n"); @@ -580,19 +332,12 @@ pub fn get_flags_section(signature: &Signature) -> String { ) } else { format!(" --{}\n {}\n", flag.long, flag.desc) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }; long_desc.push_str(&msg); } long_desc } -<<<<<<< HEAD -pub fn get_brief_help(cmd: &dyn WholeStreamCommand, scope: &Scope) -> String { - get_documentation( - cmd, - scope, -======= pub fn get_brief_help( sig: &Signature, examples: &[Example], @@ -604,7 +349,6 @@ pub fn get_brief_help( examples, engine_state, stack, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce &DocumentationConfig { no_subcommands: false, no_color: false, @@ -613,10 +357,6 @@ pub fn get_brief_help( ) } -<<<<<<< HEAD -pub fn get_full_help(cmd: &dyn WholeStreamCommand, scope: &Scope) -> String { - get_documentation(cmd, scope, &DocumentationConfig::default()) -======= pub fn get_full_help( sig: &Signature, examples: &[Example], @@ -630,5 +370,4 @@ pub fn get_full_help( stack, &DocumentationConfig::default(), ) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu-engine/src/lib.rs b/crates/nu-engine/src/lib.rs index 359746fcb7..9de7dae381 100644 --- a/crates/nu-engine/src/lib.rs +++ b/crates/nu-engine/src/lib.rs @@ -1,45 +1,3 @@ -<<<<<<< HEAD -mod call_info; -mod command_args; -mod config_holder; -pub mod documentation; -mod env; -pub mod evaluate; -pub mod evaluation_context; -mod example; -pub mod filesystem; -mod from_value; -mod maybe_text_codec; -pub mod plugin; -mod print; -pub mod script; -pub mod shell; -mod types; -mod whole_stream_command; - -pub use crate::call_info::UnevaluatedCallInfo; -pub use crate::command_args::{CommandArgs, RunnableContext}; -pub use crate::config_holder::ConfigHolder; -pub use crate::documentation::{generate_docs, get_brief_help, get_documentation, get_full_help}; -pub use crate::env::host::FakeHost; -pub use crate::env::host::Host; -pub use crate::evaluate::block::run_block; -pub use crate::evaluate::envvar::EnvVar; -pub use crate::evaluate::scope::Scope; -pub use crate::evaluate::{evaluator, evaluator::evaluate_baseline_expr}; -pub use crate::evaluation_context::EvaluationContext; -pub use crate::example::Example; -pub use crate::filesystem::dir_info::{DirBuilder, DirInfo, FileInfo}; -pub use crate::filesystem::filesystem_shell::FilesystemShell; -pub use crate::from_value::FromValue; -pub use crate::maybe_text_codec::{BufCodecReader, MaybeTextCodec, StringOrBinary}; -pub use crate::print::maybe_print_errors; -pub use crate::shell::painter::Painter; -pub use crate::shell::palette::{DefaultPalette, Palette}; -pub use crate::shell::shell_manager::ShellManager; -pub use crate::shell::value_shell; -pub use crate::whole_stream_command::{whole_stream_command, Command, WholeStreamCommand}; -======= mod call_ext; pub mod column; pub mod documentation; @@ -56,4 +14,3 @@ pub use eval::{ eval_operator, eval_subexpression, }; pub use glob_from::glob_from; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-json/Cargo.toml b/crates/nu-json/Cargo.toml index 6e476265b2..58ec91278e 100644 --- a/crates/nu-json/Cargo.toml +++ b/crates/nu-json/Cargo.toml @@ -1,17 +1,10 @@ [package] authors = ["The Nu Project Contributors", "Christian Zangl "] description = "Fork of serde-hjson" -<<<<<<< HEAD -edition = "2018" -license = "MIT" -name = "nu-json" -version = "0.43.0" -======= edition = "2021" license = "MIT" name = "nu-json" -version = "0.37.1" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +version = "0.59.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -27,10 +20,5 @@ lazy_static = "1" linked-hash-map = { version="0.5", optional=true } [dev-dependencies] -<<<<<<< HEAD -nu-path = { version = "0.43.0", path="../nu-path" } -nu-test-support = { version = "0.43.0", path="../nu-test-support" } -======= -nu-path = { version = "0.37.1", path="../nu-path" } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +nu-path = { path="../nu-path", version = "0.59.0" } serde_json = "1.0.39" diff --git a/crates/nu-json/LICENSE b/crates/nu-json/LICENSE new file mode 100644 index 0000000000..e6fee54fa8 --- /dev/null +++ b/crates/nu-json/LICENSE @@ -0,0 +1,29 @@ +The MIT License (MIT) + +Copyright (c) 2014 The Rust Project Developers +Copyright (c) 2016 Christian Zangl +Copyright (c) 2020 The Nu Project Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/crates/nu-json/src/builder.rs b/crates/nu-json/src/builder.rs new file mode 100644 index 0000000000..a69eee28cd --- /dev/null +++ b/crates/nu-json/src/builder.rs @@ -0,0 +1,115 @@ +use serde::ser; + +use crate::value::{self, Map, Value}; + +/// This structure provides a simple interface for constructing a JSON array. +pub struct ArrayBuilder { + array: Vec, +} + +impl Default for ArrayBuilder { + fn default() -> Self { + Self::new() + } +} + +impl ArrayBuilder { + /// Construct an `ObjectBuilder`. + pub fn new() -> ArrayBuilder { + ArrayBuilder { array: Vec::new() } + } + + /// Return the constructed `Value`. + pub fn unwrap(self) -> Value { + Value::Array(self.array) + } + + /// Insert a value into the array. + pub fn push(mut self, v: T) -> ArrayBuilder { + self.array + .push(value::to_value(&v).expect("failed to serialize")); + self + } + + /// Creates and passes an `ArrayBuilder` into a closure, then inserts the resulting array into + /// this array. + pub fn push_array(mut self, f: F) -> ArrayBuilder + where + F: FnOnce(ArrayBuilder) -> ArrayBuilder, + { + let builder = ArrayBuilder::new(); + self.array.push(f(builder).unwrap()); + self + } + + /// Creates and passes an `ArrayBuilder` into a closure, then inserts the resulting object into + /// this array. + pub fn push_object(mut self, f: F) -> ArrayBuilder + where + F: FnOnce(ObjectBuilder) -> ObjectBuilder, + { + let builder = ObjectBuilder::new(); + self.array.push(f(builder).unwrap()); + self + } +} + +/// This structure provides a simple interface for constructing a JSON object. +pub struct ObjectBuilder { + object: Map, +} + +impl Default for ObjectBuilder { + fn default() -> Self { + Self::new() + } +} + +impl ObjectBuilder { + /// Construct an `ObjectBuilder`. + pub fn new() -> ObjectBuilder { + ObjectBuilder { object: Map::new() } + } + + /// Return the constructed `Value`. + pub fn unwrap(self) -> Value { + Value::Object(self.object) + } + + /// Insert a key-value pair into the object. + pub fn insert(mut self, key: S, value: V) -> ObjectBuilder + where + S: Into, + V: ser::Serialize, + { + self.object.insert( + key.into(), + value::to_value(&value).expect("failed to serialize"), + ); + self + } + + /// Creates and passes an `ObjectBuilder` into a closure, then inserts the resulting array into + /// this object. + pub fn insert_array(mut self, key: S, f: F) -> ObjectBuilder + where + S: Into, + F: FnOnce(ArrayBuilder) -> ArrayBuilder, + { + let builder = ArrayBuilder::new(); + self.object.insert(key.into(), f(builder).unwrap()); + self + } + + /// Creates and passes an `ObjectBuilder` into a closure, then inserts the resulting object into + /// this object. + pub fn insert_object(mut self, key: S, f: F) -> ObjectBuilder + where + S: Into, + F: FnOnce(ObjectBuilder) -> ObjectBuilder, + { + let builder = ObjectBuilder::new(); + self.object.insert(key.into(), f(builder).unwrap()); + self + } +} diff --git a/crates/nu-json/src/de.rs b/crates/nu-json/src/de.rs new file mode 100644 index 0000000000..430aa68b01 --- /dev/null +++ b/crates/nu-json/src/de.rs @@ -0,0 +1,833 @@ +//! Hjson Deserialization +//! +//! This module provides for Hjson deserialization with the type `Deserializer`. + +use std::char; +use std::io; +use std::marker::PhantomData; +use std::str; + +use serde::de; + +use super::error::{Error, ErrorCode, Result}; +use super::util::StringReader; +use super::util::{Number, ParseNumber}; + +enum State { + Normal, + Root, + Keyname, +} + +/// A structure that deserializes Hjson into Rust values. +pub struct Deserializer> { + rdr: StringReader, + str_buf: Vec, + state: State, +} + +// macro_rules! try_or_invalid { +// ($self_:expr, $e:expr) => { +// match $e { +// Some(v) => v, +// None => { return Err($self_.error(ErrorCode::InvalidNumber)); } +// } +// } +// } + +impl Deserializer +where + Iter: Iterator, +{ + /// Creates the Hjson parser from an `std::iter::Iterator`. + #[inline] + pub fn new(rdr: Iter) -> Deserializer { + Deserializer { + rdr: StringReader::new(rdr), + str_buf: Vec::with_capacity(128), + state: State::Normal, + } + } + + /// Creates the Hjson parser from an `std::iter::Iterator`. + #[inline] + pub fn new_for_root(rdr: Iter) -> Deserializer { + let mut res = Deserializer::new(rdr); + res.state = State::Root; + res + } + + /// The `Deserializer::end` method should be called after a value has been fully deserialized. + /// This allows the `Deserializer` to validate that the input stream is at the end or that it + /// only has trailing whitespace. + #[inline] + pub fn end(&mut self) -> Result<()> { + self.rdr.parse_whitespace()?; + if self.rdr.eof()? { + Ok(()) + } else { + Err(self.rdr.error(ErrorCode::TrailingCharacters)) + } + } + + fn is_punctuator_char(&mut self, ch: u8) -> bool { + matches!(ch, b'{' | b'}' | b'[' | b']' | b',' | b':') + } + + fn parse_keyname<'de, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + // quotes for keys are optional in Hjson + // unless they include {}[],: or whitespace. + // assume whitespace was already eaten + + self.str_buf.clear(); + + let mut space: Option = None; + loop { + let ch = self.rdr.next_char_or_null()?; + + if ch == b':' { + if self.str_buf.is_empty() { + return Err(self.rdr.error(ErrorCode::Custom( + "Found ':' but no key name (for an empty key name use quotes)".to_string(), + ))); + } else if space.is_some() + && space.expect("Internal error: json parsing") != self.str_buf.len() + { + return Err(self.rdr.error(ErrorCode::Custom( + "Found whitespace in your key name (use quotes to include)".to_string(), + ))); + } + self.rdr.uneat_char(ch); + let s = str::from_utf8(&self.str_buf).expect("Internal error: json parsing"); + return visitor.visit_str(s); + } else if ch <= b' ' { + if ch == 0 { + return Err(self.rdr.error(ErrorCode::EofWhileParsingObject)); + } else if space.is_none() { + space = Some(self.str_buf.len()); + } + } else if self.is_punctuator_char(ch) { + return Err(self.rdr.error(ErrorCode::Custom("Found a punctuator where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)".to_string()))); + } else { + self.str_buf.push(ch); + } + } + } + + fn parse_value<'de, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.rdr.parse_whitespace()?; + + if self.rdr.eof()? { + return Err(self.rdr.error(ErrorCode::EofWhileParsingValue)); + } + + match self.state { + State::Keyname => { + self.state = State::Normal; + return self.parse_keyname(visitor); + } + State::Root => { + self.state = State::Normal; + return self.visit_map(true, visitor); + } + _ => {} + } + + match self.rdr.peek_or_null()? { + /* + b'-' => { + self.rdr.eat_char(); + self.parse_integer(false, visitor) + } + b'0' ... b'9' => { + self.parse_integer(true, visitor) + } + */ + b'"' => { + self.rdr.eat_char(); + self.parse_string()?; + let s = str::from_utf8(&self.str_buf).expect("Internal error: json parsing"); + visitor.visit_str(s) + } + b'[' => { + self.rdr.eat_char(); + let ret = visitor.visit_seq(SeqVisitor::new(self))?; + self.rdr.parse_whitespace()?; + match self.rdr.next_char()? { + Some(b']') => Ok(ret), + Some(_) => Err(self.rdr.error(ErrorCode::TrailingCharacters)), + None => Err(self.rdr.error(ErrorCode::EofWhileParsingList)), + } + } + b'{' => { + self.rdr.eat_char(); + self.visit_map(false, visitor) + } + b'\x00' => Err(self.rdr.error(ErrorCode::ExpectedSomeValue)), + _ => self.parse_tfnns(visitor), + } + } + + fn visit_map<'de, V>(&mut self, root: bool, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let ret = visitor.visit_map(MapVisitor::new(self, root))?; + self.rdr.parse_whitespace()?; + match self.rdr.next_char()? { + Some(b'}') => { + if !root { + Ok(ret) + } else { + Err(self.rdr.error(ErrorCode::TrailingCharacters)) + } // todo + } + Some(_) => Err(self.rdr.error(ErrorCode::TrailingCharacters)), + None => { + if root { + Ok(ret) + } else { + Err(self.rdr.error(ErrorCode::EofWhileParsingObject)) + } + } + } + } + + fn parse_ident(&mut self, ident: &[u8]) -> Result<()> { + for c in ident { + if Some(*c) != self.rdr.next_char()? { + return Err(self.rdr.error(ErrorCode::ExpectedSomeIdent)); + } + } + + Ok(()) + } + + fn parse_tfnns<'de, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + // Hjson strings can be quoteless + // returns string, true, false, or null. + self.str_buf.clear(); + + let first = self.rdr.peek()?.expect("Internal error: json parsing"); + + if self.is_punctuator_char(first) { + return Err(self.rdr.error(ErrorCode::PunctuatorInQlString)); + } + + loop { + let ch = self.rdr.next_char_or_null()?; + + let is_eol = ch == b'\r' || ch == b'\n' || ch == b'\x00'; + let is_comment = ch == b'#' + || if ch == b'/' { + let next = self.rdr.peek_or_null()?; + next == b'/' || next == b'*' + } else { + false + }; + if is_eol || is_comment || ch == b',' || ch == b'}' || ch == b']' { + let chf = self.str_buf[0]; + match chf { + b'f' => { + if str::from_utf8(&self.str_buf) + .expect("Internal error: json parsing") + .trim() + == "false" + { + self.rdr.uneat_char(ch); + return visitor.visit_bool(false); + } + } + b'n' => { + if str::from_utf8(&self.str_buf) + .expect("Internal error: json parsing") + .trim() + == "null" + { + self.rdr.uneat_char(ch); + return visitor.visit_unit(); + } + } + b't' => { + if str::from_utf8(&self.str_buf) + .expect("Internal error: json parsing") + .trim() + == "true" + { + self.rdr.uneat_char(ch); + return visitor.visit_bool(true); + } + } + _ => { + if chf == b'-' || (b'0'..=b'9').contains(&chf) { + let mut pn = ParseNumber::new(self.str_buf.iter().copied()); + match pn.parse(false) { + Ok(Number::F64(v)) => { + self.rdr.uneat_char(ch); + return visitor.visit_f64(v); + } + Ok(Number::U64(v)) => { + self.rdr.uneat_char(ch); + return visitor.visit_u64(v); + } + Ok(Number::I64(v)) => { + self.rdr.uneat_char(ch); + return visitor.visit_i64(v); + } + Err(_) => {} // not a number, continue + } + } + } + } + if is_eol { + // remove any whitespace at the end (ignored in quoteless strings) + return visitor.visit_str( + str::from_utf8(&self.str_buf) + .expect("Internal error: json parsing") + .trim(), + ); + } + } + self.str_buf.push(ch); + + if self.str_buf == b"'''" { + return self.parse_ml_string(visitor); + } + } + } + + fn decode_hex_escape(&mut self) -> Result { + let mut i = 0; + let mut n = 0u16; + while i < 4 && !self.rdr.eof()? { + n = match self.rdr.next_char_or_null()? { + c @ b'0'..=b'9' => n * 16_u16 + ((c as u16) - (b'0' as u16)), + b'a' | b'A' => n * 16_u16 + 10_u16, + b'b' | b'B' => n * 16_u16 + 11_u16, + b'c' | b'C' => n * 16_u16 + 12_u16, + b'd' | b'D' => n * 16_u16 + 13_u16, + b'e' | b'E' => n * 16_u16 + 14_u16, + b'f' | b'F' => n * 16_u16 + 15_u16, + _ => { + return Err(self.rdr.error(ErrorCode::InvalidEscape)); + } + }; + + i += 1; + } + + // Error out if we didn't parse 4 digits. + if i != 4 { + return Err(self.rdr.error(ErrorCode::InvalidEscape)); + } + + Ok(n) + } + + fn ml_skip_white(&mut self) -> Result { + match self.rdr.peek_or_null()? { + b' ' | b'\t' | b'\r' => { + self.rdr.eat_char(); + Ok(true) + } + _ => Ok(false), + } + } + + fn ml_skip_indent(&mut self, indent: usize) -> Result<()> { + let mut skip = indent; + while self.ml_skip_white()? && skip > 0 { + skip -= 1; + } + Ok(()) + } + + fn parse_ml_string<'de, V>(&mut self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.str_buf.clear(); + + // Parse a multiline string value. + let mut triple = 0; + + // we are at ''' +1 - get indent + let (_, col) = self.rdr.pos(); + let indent = col - 4; + + // skip white/to (newline) + while self.ml_skip_white()? {} + if self.rdr.peek_or_null()? == b'\n' { + self.rdr.eat_char(); + self.ml_skip_indent(indent)?; + } + + // When parsing multiline string values, we must look for ' characters. + loop { + if self.rdr.eof()? { + return Err(self.rdr.error(ErrorCode::EofWhileParsingString)); + } // todo error("Bad multiline string"); + let ch = self.rdr.next_char_or_null()?; + + if ch == b'\'' { + triple += 1; + if triple == 3 { + if self.str_buf.last() == Some(&b'\n') { + self.str_buf.pop(); + } + let res = str::from_utf8(&self.str_buf).expect("Internal error: json parsing"); + //todo if (self.str_buf.slice(-1) === '\n') self.str_buf=self.str_buf.slice(0, -1); // remove last EOL + return visitor.visit_str(res); + } else { + continue; + } + } + + while triple > 0 { + self.str_buf.push(b'\''); + triple -= 1; + } + + if ch != b'\r' { + self.str_buf.push(ch); + } + if ch == b'\n' { + self.ml_skip_indent(indent)?; + } + } + } + + fn parse_string(&mut self) -> Result<()> { + self.str_buf.clear(); + + loop { + let ch = match self.rdr.next_char()? { + Some(ch) => ch, + None => { + return Err(self.rdr.error(ErrorCode::EofWhileParsingString)); + } + }; + + match ch { + b'"' => { + return Ok(()); + } + b'\\' => { + let ch = match self.rdr.next_char()? { + Some(ch) => ch, + None => { + return Err(self.rdr.error(ErrorCode::EofWhileParsingString)); + } + }; + + match ch { + b'"' => self.str_buf.push(b'"'), + b'\\' => self.str_buf.push(b'\\'), + b'/' => self.str_buf.push(b'/'), + b'b' => self.str_buf.push(b'\x08'), + b'f' => self.str_buf.push(b'\x0c'), + b'n' => self.str_buf.push(b'\n'), + b'r' => self.str_buf.push(b'\r'), + b't' => self.str_buf.push(b'\t'), + b'u' => { + let c = match self.decode_hex_escape()? { + 0xDC00..=0xDFFF => { + return Err(self + .rdr + .error(ErrorCode::LoneLeadingSurrogateInHexEscape)); + } + + // Non-BMP characters are encoded as a sequence of + // two hex escapes, representing UTF-16 surrogates. + n1 @ 0xD800..=0xDBFF => { + match (self.rdr.next_char()?, self.rdr.next_char()?) { + (Some(b'\\'), Some(b'u')) => (), + _ => { + return Err(self + .rdr + .error(ErrorCode::UnexpectedEndOfHexEscape)); + } + } + + let n2 = self.decode_hex_escape()?; + + if !(0xDC00..=0xDFFF).contains(&n2) { + return Err(self + .rdr + .error(ErrorCode::LoneLeadingSurrogateInHexEscape)); + } + + let n = (((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32) + + 0x1_0000; + + match char::from_u32(n as u32) { + Some(c) => c, + None => { + return Err(self + .rdr + .error(ErrorCode::InvalidUnicodeCodePoint)); + } + } + } + + n => match char::from_u32(n as u32) { + Some(c) => c, + None => { + return Err(self + .rdr + .error(ErrorCode::InvalidUnicodeCodePoint)); + } + }, + }; + + self.str_buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()); + } + _ => { + return Err(self.rdr.error(ErrorCode::InvalidEscape)); + } + } + } + ch => { + self.str_buf.push(ch); + } + } + } + } + + fn parse_object_colon(&mut self) -> Result<()> { + self.rdr.parse_whitespace()?; + + match self.rdr.next_char()? { + Some(b':') => Ok(()), + Some(_) => Err(self.rdr.error(ErrorCode::ExpectedColon)), + None => Err(self.rdr.error(ErrorCode::EofWhileParsingObject)), + } + } +} + +impl<'de, 'a, Iter> de::Deserializer<'de> for &'a mut Deserializer +where + Iter: Iterator, +{ + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + if let State::Root = self.state {} + + self.parse_value(visitor) + } + + /// Parses a `null` as a None, and any other values as a `Some(...)`. + #[inline] + fn deserialize_option(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.rdr.parse_whitespace()?; + + match self.rdr.peek_or_null()? { + b'n' => { + self.rdr.eat_char(); + self.parse_ident(b"ull")?; + visitor.visit_none() + } + _ => visitor.visit_some(self), + } + } + + /// Parses a newtype struct as the underlying value. + #[inline] + fn deserialize_newtype_struct(self, _name: &str, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + serde::forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf unit unit_struct seq tuple map + tuple_struct struct enum identifier ignored_any + } +} + +struct SeqVisitor<'a, Iter: 'a + Iterator> { + de: &'a mut Deserializer, +} + +impl<'a, Iter: Iterator> SeqVisitor<'a, Iter> { + fn new(de: &'a mut Deserializer) -> Self { + SeqVisitor { de } + } +} + +impl<'de, 'a, Iter> de::SeqAccess<'de> for SeqVisitor<'a, Iter> +where + Iter: Iterator, +{ + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: de::DeserializeSeed<'de>, + { + self.de.rdr.parse_whitespace()?; + + match self.de.rdr.peek()? { + Some(b']') => { + return Ok(None); + } + Some(_) => {} + None => { + return Err(self.de.rdr.error(ErrorCode::EofWhileParsingList)); + } + } + + let value = seed.deserialize(&mut *self.de)?; + + // in Hjson the comma is optional and trailing commas are allowed + self.de.rdr.parse_whitespace()?; + if self.de.rdr.peek()? == Some(b',') { + self.de.rdr.eat_char(); + self.de.rdr.parse_whitespace()?; + } + + Ok(Some(value)) + } +} + +struct MapVisitor<'a, Iter: 'a + Iterator> { + de: &'a mut Deserializer, + first: bool, + root: bool, +} + +impl<'a, Iter: Iterator> MapVisitor<'a, Iter> { + fn new(de: &'a mut Deserializer, root: bool) -> Self { + MapVisitor { + de, + first: true, + root, + } + } +} + +impl<'de, 'a, Iter> de::MapAccess<'de> for MapVisitor<'a, Iter> +where + Iter: Iterator, +{ + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result> + where + K: de::DeserializeSeed<'de>, + { + self.de.rdr.parse_whitespace()?; + + if self.first { + self.first = false; + } else if self.de.rdr.peek()? == Some(b',') { + // in Hjson the comma is optional and trailing commas are allowed + self.de.rdr.eat_char(); + self.de.rdr.parse_whitespace()?; + } + + match self.de.rdr.peek()? { + Some(b'}') => return Ok(None), // handled later for root + Some(_) => {} + None => { + if self.root { + return Ok(None); + } else { + return Err(self.de.rdr.error(ErrorCode::EofWhileParsingObject)); + } + } + } + + match self.de.rdr.peek()? { + Some(ch) => { + self.de.state = if ch == b'"' { + State::Normal + } else { + State::Keyname + }; + Ok(Some(seed.deserialize(&mut *self.de)?)) + } + None => Err(self.de.rdr.error(ErrorCode::EofWhileParsingValue)), + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: de::DeserializeSeed<'de>, + { + self.de.parse_object_colon()?; + + seed.deserialize(&mut *self.de) + } +} + +impl<'de, 'a, Iter> de::VariantAccess<'de> for &'a mut Deserializer +where + Iter: Iterator, +{ + type Error = Error; + + fn unit_variant(self) -> Result<()> { + de::Deserialize::deserialize(self) + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self) + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + de::Deserializer::deserialize_any(self, visitor) + } + + fn struct_variant(self, _fields: &'static [&'static str], visitor: V) -> Result + where + V: de::Visitor<'de>, + { + de::Deserializer::deserialize_any(self, visitor) + } +} + +////////////////////////////////////////////////////////////////////////////// + +/// Iterator that deserializes a stream into multiple Hjson values. +pub struct StreamDeserializer +where + Iter: Iterator, + T: de::DeserializeOwned, +{ + deser: Deserializer, + _marker: PhantomData, +} + +impl StreamDeserializer +where + Iter: Iterator, + T: de::DeserializeOwned, +{ + /// Returns an `Iterator` of decoded Hjson values from an iterator over + /// `Iterator`. + pub fn new(iter: Iter) -> StreamDeserializer { + StreamDeserializer { + deser: Deserializer::new(iter), + _marker: PhantomData, + } + } +} + +impl Iterator for StreamDeserializer +where + Iter: Iterator, + T: de::DeserializeOwned, +{ + type Item = Result; + + fn next(&mut self) -> Option> { + // skip whitespaces, if any + // this helps with trailing whitespaces, since whitespaces between + // values are handled for us. + if let Err(e) = self.deser.rdr.parse_whitespace() { + return Some(Err(e)); + }; + + match self.deser.rdr.eof() { + Ok(true) => None, + Ok(false) => match de::Deserialize::deserialize(&mut self.deser) { + Ok(v) => Some(Ok(v)), + Err(e) => Some(Err(e)), + }, + Err(e) => Some(Err(e)), + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +/// Decodes a Hjson value from an iterator over an iterator +/// `Iterator`. +pub fn from_iter(iter: I) -> Result +where + I: Iterator>, + T: de::DeserializeOwned, +{ + let fold: io::Result> = iter.collect(); + + if let Err(e) = fold { + return Err(Error::Io(e)); + } + + let bytes = fold.expect("Internal error: json parsing"); + + // deserialize tries first to decode with legacy support (new_for_root) + // and then with the standard method if this fails. + // todo: add compile switch + + // deserialize and make sure the whole stream has been consumed + let mut de = Deserializer::new_for_root(bytes.iter().copied()); + de::Deserialize::deserialize(&mut de) + .and_then(|x| de.end().map(|()| x)) + .or_else(|_| { + let mut de2 = Deserializer::new(bytes.iter().copied()); + de::Deserialize::deserialize(&mut de2).and_then(|x| de2.end().map(|()| x)) + }) + + /* without legacy support: + // deserialize and make sure the whole stream has been consumed + let mut de = Deserializer::new(bytes.iter().map(|b| *b)); + let value = match de::Deserialize::deserialize(&mut de) + .and_then(|x| { try!(de.end()); Ok(x) }) + { + Ok(v) => Ok(v), + Err(e) => Err(e), + }; + */ +} + +/// Decodes a Hjson value from a `std::io::Read`. +pub fn from_reader(rdr: R) -> Result +where + R: io::Read, + T: de::DeserializeOwned, +{ + from_iter(rdr.bytes()) +} + +/// Decodes a Hjson value from a byte slice `&[u8]`. +pub fn from_slice(v: &[u8]) -> Result +where + T: de::DeserializeOwned, +{ + from_iter(v.iter().map(|&byte| Ok(byte))) +} + +/// Decodes a Hjson value from a `&str`. +pub fn from_str(s: &str) -> Result +where + T: de::DeserializeOwned, +{ + from_slice(s.as_bytes()) +} diff --git a/crates/nu-json/src/error.rs b/crates/nu-json/src/error.rs new file mode 100644 index 0000000000..33d417c62a --- /dev/null +++ b/crates/nu-json/src/error.rs @@ -0,0 +1,166 @@ +//! JSON Errors +//! +//! This module is centered around the `Error` and `ErrorCode` types, which represents all possible +//! `serde_hjson` errors. + +use std::error; +use std::fmt; +use std::io; +use std::result; +use std::string::FromUtf8Error; + +use serde::de; +use serde::ser; + +/// The errors that can arise while parsing a JSON stream. +#[derive(Clone, PartialEq)] +pub enum ErrorCode { + /// Catchall for syntax error messages + Custom(String), + + /// EOF while parsing a list. + EofWhileParsingList, + + /// EOF while parsing an object. + EofWhileParsingObject, + + /// EOF while parsing a string. + EofWhileParsingString, + + /// EOF while parsing a JSON value. + EofWhileParsingValue, + + /// Expected this character to be a `':'`. + ExpectedColon, + + /// Expected this character to be either a `','` or a `]`. + ExpectedListCommaOrEnd, + + /// Expected this character to be either a `','` or a `}`. + ExpectedObjectCommaOrEnd, + + /// Expected to parse either a `true`, `false`, or a `null`. + ExpectedSomeIdent, + + /// Expected this character to start a JSON value. + ExpectedSomeValue, + + /// Invalid hex escape code. + InvalidEscape, + + /// Invalid number. + InvalidNumber, + + /// Invalid Unicode code point. + InvalidUnicodeCodePoint, + + /// Object key is not a string. + KeyMustBeAString, + + /// Lone leading surrogate in hex escape. + LoneLeadingSurrogateInHexEscape, + + /// JSON has non-whitespace trailing characters after the value. + TrailingCharacters, + + /// Unexpected end of hex escape. + UnexpectedEndOfHexEscape, + + /// Found a punctuator character when expecting a quoteless string. + PunctuatorInQlString, +} + +impl fmt::Debug for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + //use std::fmt::Debug; + + match *self { + ErrorCode::Custom(ref msg) => write!(f, "{}", msg), + ErrorCode::EofWhileParsingList => "EOF while parsing a list".fmt(f), + ErrorCode::EofWhileParsingObject => "EOF while parsing an object".fmt(f), + ErrorCode::EofWhileParsingString => "EOF while parsing a string".fmt(f), + ErrorCode::EofWhileParsingValue => "EOF while parsing a value".fmt(f), + ErrorCode::ExpectedColon => "expected `:`".fmt(f), + ErrorCode::ExpectedListCommaOrEnd => "expected `,` or `]`".fmt(f), + ErrorCode::ExpectedObjectCommaOrEnd => "expected `,` or `}`".fmt(f), + ErrorCode::ExpectedSomeIdent => "expected ident".fmt(f), + ErrorCode::ExpectedSomeValue => "expected value".fmt(f), + ErrorCode::InvalidEscape => "invalid escape".fmt(f), + ErrorCode::InvalidNumber => "invalid number".fmt(f), + ErrorCode::InvalidUnicodeCodePoint => "invalid Unicode code point".fmt(f), + ErrorCode::KeyMustBeAString => "key must be a string".fmt(f), + ErrorCode::LoneLeadingSurrogateInHexEscape => { + "lone leading surrogate in hex escape".fmt(f) + } + ErrorCode::TrailingCharacters => "trailing characters".fmt(f), + ErrorCode::UnexpectedEndOfHexEscape => "unexpected end of hex escape".fmt(f), + ErrorCode::PunctuatorInQlString => { + "found a punctuator character when expecting a quoteless string".fmt(f) + } + } + } +} + +/// This type represents all possible errors that can occur when serializing or deserializing a +/// value into JSON. +#[derive(Debug)] +pub enum Error { + /// The JSON value had some syntactic error. + Syntax(ErrorCode, usize, usize), + + /// Some IO error occurred when serializing or deserializing a value. + Io(io::Error), + + /// Some UTF8 error occurred while serializing or deserializing a value. + FromUtf8(FromUtf8Error), +} + +impl error::Error for Error { + fn cause(&self) -> Option<&dyn error::Error> { + match *self { + Error::Io(ref error) => Some(error), + Error::FromUtf8(ref error) => Some(error), + _ => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Syntax(ref code, line, col) => { + write!(fmt, "{:?} at line {} column {}", code, line, col) + } + Error::Io(ref error) => fmt::Display::fmt(error, fmt), + Error::FromUtf8(ref error) => fmt::Display::fmt(error, fmt), + } + } +} + +impl From for Error { + fn from(error: io::Error) -> Error { + Error::Io(error) + } +} + +impl From for Error { + fn from(error: FromUtf8Error) -> Error { + Error::FromUtf8(error) + } +} + +impl de::Error for Error { + fn custom(msg: T) -> Error { + Error::Syntax(ErrorCode::Custom(msg.to_string()), 0, 0) + } +} + +impl ser::Error for Error { + /// Raised when there is general error when deserializing a type. + fn custom(msg: T) -> Error { + Error::Syntax(ErrorCode::Custom(msg.to_string()), 0, 0) + } +} + +/// Helper alias for `Result` objects that return a JSON `Error`. +pub type Result = result::Result; diff --git a/crates/nu-json/src/lib.rs b/crates/nu-json/src/lib.rs index 98f58f64ff..02b792e53b 100644 --- a/crates/nu-json/src/lib.rs +++ b/crates/nu-json/src/lib.rs @@ -2,11 +2,7 @@ pub use self::de::{ from_iter, from_reader, from_slice, from_str, Deserializer, StreamDeserializer, }; pub use self::error::{Error, ErrorCode, Result}; -<<<<<<< HEAD -pub use self::ser::{to_string, to_vec, to_writer, Serializer}; -======= pub use self::ser::{to_string, to_string_raw, to_vec, to_writer, Serializer}; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub use self::value::{from_value, to_value, Map, Value}; pub mod builder; diff --git a/crates/nu-json/src/ser.rs b/crates/nu-json/src/ser.rs index 96ae4238b7..4826c34c4f 100644 --- a/crates/nu-json/src/ser.rs +++ b/crates/nu-json/src/ser.rs @@ -4,20 +4,13 @@ use std::fmt::{Display, LowerExp}; use std::io; -<<<<<<< HEAD -======= use std::io::{BufRead, BufReader}; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use std::num::FpCategory; use super::error::{Error, ErrorCode, Result}; use serde::ser; -<<<<<<< HEAD -use super::util::ParseNumber; -======= //use super::util::ParseNumber; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use regex::Regex; @@ -738,13 +731,6 @@ impl<'a> Formatter for HjsonFormatter<'a> { writer.write_all(&[ch]).map_err(From::from) } -<<<<<<< HEAD - fn comma(&mut self, writer: &mut W, _: bool) -> Result<()> - where - W: io::Write, - { - writer.write_all(b"\n")?; -======= fn comma(&mut self, writer: &mut W, first: bool) -> Result<()> where W: io::Write, @@ -754,7 +740,6 @@ impl<'a> Formatter for HjsonFormatter<'a> { } else { writer.write_all(b"\n")?; } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce indent(writer, self.current_indent, self.indent) } @@ -868,18 +853,11 @@ where // Check if we can insert this string without quotes // see hjson syntax (must not parse as true, false, null or number) -<<<<<<< HEAD - let mut pn = ParseNumber::new(value.bytes()); - let is_number = pn.parse(true).is_ok(); - - if is_number || NEEDS_QUOTES.is_match(value) || STARTS_WITH_KEYWORD.is_match(value) { -======= //let mut pn = ParseNumber::new(value.bytes()); //let is_number = pn.parse(true).is_ok(); if true { // is_number || NEEDS_QUOTES.is_match(value) || STARTS_WITH_KEYWORD.is_match(value) { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce // First check if the string can be expressed in multiline format or // we must replace the offending characters with safe escape sequences. @@ -941,19 +919,11 @@ where } // Check if we can insert this name without quotes -<<<<<<< HEAD - if NEEDS_ESCAPE_NAME.is_match(value) { - escape_bytes(wr, value.as_bytes()).map_err(From::from) - } else { - wr.write_all(value.as_bytes()).map_err(From::from) - } -======= //if NEEDS_ESCAPE_NAME.is_match(value) { escape_bytes(wr, value.as_bytes()).map_err(From::from) // } else { // wr.write_all(value.as_bytes()).map_err(From::from) // } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[inline] @@ -961,16 +931,11 @@ fn escape_char(wr: &mut W, value: char) -> Result<()> where W: io::Write, { -<<<<<<< HEAD - let mut scratch = [0_u8; 4]; - escape_bytes(wr, value.encode_utf8(&mut scratch).as_bytes()) -======= // FIXME: this allocation is required in order to be compatible with stable // rust, which doesn't support encoding a `char` into a stack buffer. let mut s = String::new(); s.push(value); escape_bytes(wr, s.as_bytes()) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } fn fmt_f32_or_null(wr: &mut W, value: f32) -> Result<()> @@ -1059,8 +1024,6 @@ where let string = String::from_utf8(vec)?; Ok(string) } -<<<<<<< HEAD -======= /// Encode the specified struct into a Hjson `String` buffer. /// And remove all whitespace @@ -1087,4 +1050,3 @@ fn remove_json_whitespace(v: Vec) -> String { } output } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-json/src/util.rs b/crates/nu-json/src/util.rs new file mode 100644 index 0000000000..5f650b1095 --- /dev/null +++ b/crates/nu-json/src/util.rs @@ -0,0 +1,333 @@ +use std::io; +use std::str; + +use super::error::{Error, ErrorCode, Result}; + +pub struct StringReader> { + iter: Iter, + line: usize, + col: usize, + ch: Vec, +} + +impl StringReader +where + Iter: Iterator, +{ + #[inline] + pub fn new(iter: Iter) -> Self { + StringReader { + iter, + line: 1, + col: 0, + ch: Vec::new(), + } + } + + fn next(&mut self) -> Option> { + match self.iter.next() { + None => None, + Some(b'\n') => { + self.line += 1; + self.col = 0; + Some(Ok(b'\n')) + } + Some(c) => { + self.col += 1; + Some(Ok(c)) + } + } + } + + pub fn pos(&mut self) -> (usize, usize) { + (self.line, self.col) + } + + pub fn eof(&mut self) -> Result { + Ok(self.peek()?.is_none()) + } + + pub fn peek_next(&mut self, idx: usize) -> Result> { + while self.ch.len() <= idx { + match self.next() { + Some(Err(err)) => return Err(Error::Io(err)), + Some(Ok(ch)) => self.ch.push(ch), + None => return Ok(None), + } + } + Ok(Some(self.ch[idx])) + } + + // pub fn peek_next_or_null(&mut self, idx: usize) -> Result { + // Ok(try!(self.peek_next(idx)).unwrap_or(b'\x00')) + // } + + pub fn peek(&mut self) -> Result> { + self.peek_next(0) + } + + pub fn peek_or_null(&mut self) -> Result { + Ok(self.peek()?.unwrap_or(b'\x00')) + } + + pub fn eat_char(&mut self) -> u8 { + self.ch.remove(0) + } + + pub fn uneat_char(&mut self, ch: u8) { + self.ch.insert(0, ch); + } + + pub fn next_char(&mut self) -> Result> { + match self.ch.first() { + Some(&ch) => { + self.eat_char(); + Ok(Some(ch)) + } + None => match self.next() { + Some(Err(err)) => Err(Error::Io(err)), + Some(Ok(ch)) => Ok(Some(ch)), + None => Ok(None), + }, + } + } + + pub fn next_char_or_null(&mut self) -> Result { + Ok(self.next_char()?.unwrap_or(b'\x00')) + } + + fn eat_line(&mut self) -> Result<()> { + loop { + match self.peek()? { + Some(b'\n') | None => return Ok(()), + _ => {} + } + self.eat_char(); + } + } + + pub fn parse_whitespace(&mut self) -> Result<()> { + loop { + match self.peek_or_null()? { + b' ' | b'\n' | b'\t' | b'\r' => { + self.eat_char(); + } + b'#' => self.eat_line()?, + b'/' => { + match self.peek_next(1)? { + Some(b'/') => self.eat_line()?, + Some(b'*') => { + self.eat_char(); + self.eat_char(); + while !(self.peek()?.unwrap_or(b'*') == b'*' + && self.peek_next(1)?.unwrap_or(b'/') == b'/') + { + self.eat_char(); + } + self.eat_char(); + self.eat_char(); + } + Some(_) => { + self.eat_char(); + } + None => return Err(self.error(ErrorCode::TrailingCharacters)), //todo + } + } + _ => { + return Ok(()); + } + } + } + } + + pub fn error(&mut self, reason: ErrorCode) -> Error { + Error::Syntax(reason, self.line, self.col) + } +} + +pub enum Number { + I64(i64), + U64(u64), + F64(f64), +} + +pub struct ParseNumber> { + rdr: StringReader, + result: Vec, +} + +// macro_rules! try_or_invalid { +// ($e:expr) => { +// match $e { +// Some(v) => v, +// None => { return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)); } +// } +// } +// } + +impl> ParseNumber { + #[inline] + pub fn new(iter: Iter) -> Self { + ParseNumber { + rdr: StringReader::new(iter), + result: Vec::new(), + } + } + + pub fn parse(&mut self, stop_at_next: bool) -> Result { + match self.try_parse() { + Ok(()) => { + self.rdr.parse_whitespace()?; + + let mut ch = self.rdr.next_char_or_null()?; + + if stop_at_next { + let ch2 = self.rdr.peek_or_null()?; + // end scan if we find a punctuator character like ,}] or a comment + if ch == b',' + || ch == b'}' + || ch == b']' + || ch == b'#' + || ch == b'/' && (ch2 == b'/' || ch2 == b'*') + { + ch = b'\x00'; + } + } + + match ch { + b'\x00' => { + let res = + str::from_utf8(&self.result).expect("Internal error: json parsing"); + + let mut is_float = false; + for ch in res.chars() { + if ch == '.' || ch == 'e' || ch == 'E' { + is_float = true; + break; + } + } + + if is_float { + Ok(Number::F64( + res.parse::().expect("Internal error: json parsing"), + )) + } else if res.starts_with('-') { + Ok(Number::I64( + res.parse::().expect("Internal error: json parsing"), + )) + } else { + Ok(Number::U64( + res.parse::().expect("Internal error: json parsing"), + )) + } + } + _ => Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)), + } + } + Err(e) => Err(e), + } + } + + fn try_parse(&mut self) -> Result<()> { + if self.rdr.peek_or_null()? == b'-' { + self.result.push(self.rdr.eat_char()); + } + + let mut has_value = false; + + if self.rdr.peek_or_null()? == b'0' { + self.result.push(self.rdr.eat_char()); + has_value = true; + + // There can be only one leading '0'. + if let b'0'..=b'9' = self.rdr.peek_or_null()? { + return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)); + } + } + + loop { + match self.rdr.peek_or_null()? { + b'0'..=b'9' => { + self.result.push(self.rdr.eat_char()); + has_value = true; + } + b'.' => { + if !has_value { + return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)); + } + self.rdr.eat_char(); + return self.try_decimal(); + } + b'e' | b'E' => { + if !has_value { + return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)); + } + self.rdr.eat_char(); + return self.try_exponent(); + } + _ => { + if !has_value { + return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)); + } + return Ok(()); + } + } + } + } + + fn try_decimal(&mut self) -> Result<()> { + self.result.push(b'.'); + + // Make sure a digit follows the decimal place. + match self.rdr.next_char_or_null()? { + c @ b'0'..=b'9' => { + self.result.push(c); + } + _ => { + return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)); + } + }; + + while let b'0'..=b'9' = self.rdr.peek_or_null()? { + self.result.push(self.rdr.eat_char()); + } + + match self.rdr.peek_or_null()? { + b'e' | b'E' => { + self.rdr.eat_char(); + self.try_exponent() + } + _ => Ok(()), + } + } + + fn try_exponent(&mut self) -> Result<()> { + self.result.push(b'e'); + + match self.rdr.peek_or_null()? { + b'+' => { + self.result.push(self.rdr.eat_char()); + } + b'-' => { + self.result.push(self.rdr.eat_char()); + } + _ => {} + }; + + // Make sure a digit follows the exponent place. + match self.rdr.next_char_or_null()? { + c @ b'0'..=b'9' => { + self.result.push(c); + } + _ => { + return Err(Error::Syntax(ErrorCode::InvalidNumber, 0, 0)); + } + }; + + while let b'0'..=b'9' = self.rdr.peek_or_null()? { + self.result.push(self.rdr.eat_char()); + } + + Ok(()) + } +} diff --git a/crates/nu-json/src/value.rs b/crates/nu-json/src/value.rs new file mode 100644 index 0000000000..0d3533f9c8 --- /dev/null +++ b/crates/nu-json/src/value.rs @@ -0,0 +1,1158 @@ +#[cfg(not(feature = "preserve_order"))] +use std::collections::{btree_map, BTreeMap}; + +#[cfg(feature = "preserve_order")] +use linked_hash_map::{self, LinkedHashMap}; + +use std::fmt; +use std::io; +use std::str; +use std::vec; + +use num_traits::NumCast; + +use serde::de; +use serde::ser; + +use crate::error::{Error, ErrorCode}; + +type Result = std::result::Result; + +/// Represents a key/value type. +#[cfg(not(feature = "preserve_order"))] +pub type Map = BTreeMap; +/// Represents a key/value type. +#[cfg(feature = "preserve_order")] +pub type Map = LinkedHashMap; + +/// Represents the `IntoIter` type. +#[cfg(not(feature = "preserve_order"))] +pub type MapIntoIter = btree_map::IntoIter; +/// Represents the IntoIter type. +#[cfg(feature = "preserve_order")] +pub type MapIntoIter = linked_hash_map::IntoIter; + +fn map_with_capacity(size: Option) -> Map { + #[cfg(not(feature = "preserve_order"))] + { + let _ = size; + BTreeMap::new() + } + + #[cfg(feature = "preserve_order")] + { + LinkedHashMap::with_capacity(size.unwrap_or(0)) + } +} + +/// Represents a Hjson/JSON value +#[derive(Clone, PartialEq)] +pub enum Value { + /// Represents a JSON null value + Null, + + /// Represents a JSON Boolean + Bool(bool), + + /// Represents a JSON signed integer + I64(i64), + + /// Represents a JSON unsigned integer + U64(u64), + + /// Represents a JSON floating point number + F64(f64), + + /// Represents a JSON string + String(String), + + /// Represents a JSON array + Array(Vec), + + /// Represents a JSON object + Object(Map), +} + +impl Value { + /// If the `Value` is an Object, returns the value associated with the provided key. + /// Otherwise, returns None. + pub fn find<'a>(&'a self, key: &str) -> Option<&'a Value> { + match *self { + Value::Object(ref map) => map.get(key), + _ => None, + } + } + + /// Attempts to get a nested Value Object for each key in `keys`. + /// If any key is found not to exist, find_path will return None. + /// Otherwise, it will return the `Value` associated with the final key. + pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Value> { + let mut target = self; + for key in keys { + match target.find(key) { + Some(t) => { + target = t; + } + None => return None, + } + } + Some(target) + } + + /// Looks up a value by a JSON Pointer. + /// + /// JSON Pointer defines a string syntax for identifying a specific value + /// within a JavaScript Object Notation (JSON) document. + /// + /// A Pointer is a Unicode string with the reference tokens separated by `/`. + /// Inside tokens `/` is replaced by `~1` and `~` is replaced by `~0`. The + /// addressed value is returned and if there is no such value `None` is + /// returned. + /// + /// For more information read [RFC6901](https://tools.ietf.org/html/rfc6901). + pub fn pointer<'a>(&'a self, pointer: &str) -> Option<&'a Value> { + fn parse_index(s: &str) -> Option { + if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) { + return None; + } + s.parse().ok() + } + if pointer.is_empty() { + return Some(self); + } + if !pointer.starts_with('/') { + return None; + } + let mut target = self; + for escaped_token in pointer.split('/').skip(1) { + let token = escaped_token.replace("~1", "/").replace("~0", "~"); + let target_opt = match *target { + Value::Object(ref map) => map.get(&token[..]), + Value::Array(ref list) => parse_index(&token[..]).and_then(|x| list.get(x)), + _ => return None, + }; + if let Some(t) = target_opt { + target = t; + } else { + return None; + } + } + Some(target) + } + + /// If the `Value` is an Object, performs a depth-first search until + /// a value associated with the provided key is found. If no value is found + /// or the `Value` is not an Object, returns None. + pub fn search<'a>(&'a self, key: &str) -> Option<&'a Value> { + match self { + Value::Object(map) => map + .get(key) + .or_else(|| map.values().find_map(|v| v.search(key))), + _ => None, + } + } + + /// Returns true if the `Value` is an Object. Returns false otherwise. + pub fn is_object(&self) -> bool { + self.as_object().is_some() + } + + /// If the `Value` is an Object, returns the associated Map. + /// Returns None otherwise. + pub fn as_object(&self) -> Option<&Map> { + match *self { + Value::Object(ref map) => Some(map), + _ => None, + } + } + + /// If the `Value` is an Object, returns the associated mutable Map. + /// Returns None otherwise. + pub fn as_object_mut(&mut self) -> Option<&mut Map> { + match *self { + Value::Object(ref mut map) => Some(map), + _ => None, + } + } + + /// Returns true if the `Value` is an Array. Returns false otherwise. + pub fn is_array(&self) -> bool { + self.as_array().is_some() + } + + /// If the `Value` is an Array, returns the associated vector. + /// Returns None otherwise. + pub fn as_array(&self) -> Option<&Vec> { + match self { + Value::Array(array) => Some(array), + _ => None, + } + } + + /// If the `Value` is an Array, returns the associated mutable vector. + /// Returns None otherwise. + pub fn as_array_mut(&mut self) -> Option<&mut Vec> { + match self { + Value::Array(list) => Some(list), + _ => None, + } + } + + /// Returns true if the `Value` is a String. Returns false otherwise. + pub fn is_string(&self) -> bool { + self.as_str().is_some() + } + + /// If the `Value` is a String, returns the associated str. + /// Returns None otherwise. + pub fn as_str(&self) -> Option<&str> { + match self { + Value::String(s) => Some(s), + _ => None, + } + } + + /// Returns true if the `Value` is a Number. Returns false otherwise. + pub fn is_number(&self) -> bool { + matches!(self, Value::I64(_) | Value::U64(_) | Value::F64(_)) + } + + /// Returns true if the `Value` is a i64. Returns false otherwise. + pub fn is_i64(&self) -> bool { + matches!(self, Value::I64(_)) + } + + /// Returns true if the `Value` is a u64. Returns false otherwise. + pub fn is_u64(&self) -> bool { + matches!(self, Value::U64(_)) + } + + /// Returns true if the `Value` is a f64. Returns false otherwise. + pub fn is_f64(&self) -> bool { + matches!(self, Value::F64(_)) + } + + /// If the `Value` is a number, return or cast it to a i64. + /// Returns None otherwise. + pub fn as_i64(&self) -> Option { + match *self { + Value::I64(n) => Some(n), + Value::U64(n) => NumCast::from(n), + _ => None, + } + } + + /// If the `Value` is a number, return or cast it to a u64. + /// Returns None otherwise. + pub fn as_u64(&self) -> Option { + match *self { + Value::I64(n) => NumCast::from(n), + Value::U64(n) => Some(n), + _ => None, + } + } + + /// If the `Value` is a number, return or cast it to a f64. + /// Returns None otherwise. + pub fn as_f64(&self) -> Option { + match *self { + Value::I64(n) => NumCast::from(n), + Value::U64(n) => NumCast::from(n), + Value::F64(n) => Some(n), + _ => None, + } + } + + /// Returns true if the `Value` is a Boolean. Returns false otherwise. + pub fn is_boolean(&self) -> bool { + self.as_bool().is_some() + } + + /// If the `Value` is a Boolean, returns the associated bool. + /// Returns None otherwise. + pub fn as_bool(&self) -> Option { + match *self { + Value::Bool(b) => Some(b), + _ => None, + } + } + + /// Returns true if the `Value` is a Null. Returns false otherwise. + pub fn is_null(&self) -> bool { + self.as_null().is_some() + } + + /// If the `Value` is a Null, returns (). + /// Returns None otherwise. + pub fn as_null(&self) -> Option<()> { + match self { + Value::Null => Some(()), + _ => None, + } + } + + fn as_unexpected(&self) -> de::Unexpected<'_> { + match *self { + Value::Null => de::Unexpected::Unit, + Value::Bool(v) => de::Unexpected::Bool(v), + Value::I64(v) => de::Unexpected::Signed(v), + Value::U64(v) => de::Unexpected::Unsigned(v), + Value::F64(v) => de::Unexpected::Float(v), + Value::String(ref v) => de::Unexpected::Str(v), + Value::Array(_) => de::Unexpected::Seq, + Value::Object(_) => de::Unexpected::Map, + } + } +} + +impl ser::Serialize for Value { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + match *self { + Value::Null => serializer.serialize_unit(), + Value::Bool(v) => serializer.serialize_bool(v), + Value::I64(v) => serializer.serialize_i64(v), + Value::U64(v) => serializer.serialize_u64(v), + Value::F64(v) => serializer.serialize_f64(v), + Value::String(ref v) => serializer.serialize_str(v), + Value::Array(ref v) => v.serialize(serializer), + Value::Object(ref v) => v.serialize(serializer), + } + } +} + +impl<'de> de::Deserialize<'de> for Value { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> de::Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("a json value") + } + + #[inline] + fn visit_bool(self, value: bool) -> Result { + Ok(Value::Bool(value)) + } + + #[inline] + fn visit_i64(self, value: i64) -> Result { + if value < 0 { + Ok(Value::I64(value)) + } else { + Ok(Value::U64(value as u64)) + } + } + + #[inline] + fn visit_u64(self, value: u64) -> Result { + Ok(Value::U64(value)) + } + + #[inline] + fn visit_f64(self, value: f64) -> Result { + Ok(Value::F64(value)) + } + + #[inline] + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + self.visit_string(String::from(value)) + } + + #[inline] + fn visit_string(self, value: String) -> Result { + Ok(Value::String(value)) + } + + #[inline] + fn visit_none(self) -> Result { + Ok(Value::Null) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + de::Deserialize::deserialize(deserializer) + } + + #[inline] + fn visit_unit(self) -> Result { + Ok(Value::Null) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + let mut v = match seq.size_hint() { + Some(cap) => Vec::with_capacity(cap), + None => Vec::new(), + }; + + while let Some(el) = seq.next_element()? { + v.push(el) + } + + Ok(Value::Array(v)) + } + + #[inline] + fn visit_map(self, mut map: A) -> Result + where + A: de::MapAccess<'de>, + { + let mut values = map_with_capacity(map.size_hint()); + while let Some((k, v)) = map.next_entry()? { + values.insert(k, v); + } + Ok(Value::Object(values)) + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} + +struct WriterFormatter<'a, 'b: 'a> { + inner: &'a mut fmt::Formatter<'b>, +} + +impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> { + fn write(&mut self, buf: &[u8]) -> io::Result { + fn io_error(_: E) -> io::Error { + // Value does not matter because fmt::Debug and fmt::Display impls + // below just map it to fmt::Error + io::Error::new(io::ErrorKind::Other, "fmt error") + } + let s = str::from_utf8(buf).map_err(io_error)?; + self.inner.write_str(s).map_err(io_error)?; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl fmt::Debug for Value { + /// Serializes a Hjson value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut wr = WriterFormatter { inner: f }; + super::ser::to_writer(&mut wr, self).map_err(|_| fmt::Error) + } +} + +impl fmt::Display for Value { + /// Serializes a Hjson value into a string + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut wr = WriterFormatter { inner: f }; + super::ser::to_writer(&mut wr, self).map_err(|_| fmt::Error) + } +} + +impl str::FromStr for Value { + type Err = Error; + fn from_str(s: &str) -> Result { + super::de::from_str(s) + } +} + +/// Create a `serde::Serializer` that serializes a `Serialize`e into a `Value`. +#[derive(Default)] +pub struct Serializer; + +impl ser::Serializer for Serializer { + type Ok = Value; + type Error = Error; + + type SerializeSeq = SerializeVec; + type SerializeTuple = SerializeVec; + type SerializeTupleStruct = SerializeVec; + type SerializeTupleVariant = SerializeTupleVariant; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeMap; + type SerializeStructVariant = SerializeStructVariant; + + #[inline] + fn serialize_bool(self, value: bool) -> Result { + Ok(Value::Bool(value)) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result { + self.serialize_i64(value as i64) + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result { + self.serialize_i64(value as i64) + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result { + self.serialize_i64(value as i64) + } + + fn serialize_i64(self, value: i64) -> Result { + let v = if value < 0 { + Value::I64(value) + } else { + Value::U64(value as u64) + }; + Ok(v) + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result { + Ok(Value::U64(value)) + } + + #[inline] + fn serialize_f32(self, value: f32) -> Result { + self.serialize_f64(value as f64) + } + + #[inline] + fn serialize_f64(self, value: f64) -> Result { + Ok(Value::F64(value)) + } + + #[inline] + fn serialize_char(self, value: char) -> Result { + let mut s = String::new(); + s.push(value); + self.serialize_str(&s) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result { + Ok(Value::String(String::from(value))) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + let mut state = self.serialize_seq(Some(value.len()))?; + for byte in value { + ser::SerializeSeq::serialize_element(&mut state, byte)?; + } + ser::SerializeSeq::end(state) + } + + #[inline] + fn serialize_unit(self) -> Result { + Ok(Value::Null) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result { + self.serialize_unit() + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + self.serialize_str(variant) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: ?Sized + ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: ?Sized + ser::Serialize, + { + let mut values = Map::new(); + values.insert(String::from(variant), to_value(&value)?); + Ok(Value::Object(values)) + } + + #[inline] + fn serialize_none(self) -> Result { + self.serialize_unit() + } + + #[inline] + fn serialize_some(self, value: &V) -> Result + where + V: ?Sized + ser::Serialize, + { + value.serialize(self) + } + + #[inline] + fn serialize_seq(self, len: Option) -> Result { + Ok(SerializeVec { + vec: Vec::with_capacity(len.unwrap_or(0)), + }) + } + + #[inline] + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleVariant { + name: variant, + vec: Vec::with_capacity(len), + }) + } + + #[inline] + fn serialize_map(self, len: Option) -> Result { + Ok(SerializeMap { + map: map_with_capacity(len), + next_key: None, + }) + } + + #[inline] + fn serialize_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_map(Some(len)) + } + + #[inline] + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeStructVariant { + name: variant, + map: map_with_capacity(Some(len)), + }) + } +} + +#[doc(hidden)] +pub struct SerializeVec { + vec: Vec, +} + +#[doc(hidden)] +pub struct SerializeTupleVariant { + name: &'static str, + vec: Vec, +} + +#[doc(hidden)] +pub struct SerializeMap { + map: Map, + next_key: Option, +} + +#[doc(hidden)] +pub struct SerializeStructVariant { + name: &'static str, + map: Map, +} + +impl ser::SerializeSeq for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.vec.push(to_value(&value)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Array(self.vec)) + } +} + +impl ser::SerializeTuple for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + ser::SerializeSeq::end(self) + } +} + +impl ser::SerializeTupleStruct for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + ser::SerializeSeq::end(self) + } +} + +impl ser::SerializeTupleVariant for SerializeTupleVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.vec.push(to_value(&value)?); + Ok(()) + } + + fn end(self) -> Result { + let mut object = Map::new(); + + object.insert(self.name.to_owned(), Value::Array(self.vec)); + + Ok(Value::Object(object)) + } +} + +impl ser::SerializeMap for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + match to_value(key)? { + Value::String(s) => self.next_key = Some(s), + _ => return Err(Error::Syntax(ErrorCode::KeyMustBeAString, 0, 0)), + }; + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + let key = self.next_key.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let key = key.expect("serialize_value called before serialize_key"); + self.map.insert(key, to_value(value)?); + Ok(()) + } + + fn end(self) -> Result { + Ok(Value::Object(self.map)) + } +} + +impl ser::SerializeStruct for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + ser::SerializeMap::serialize_entry(self, key, value) + } + + fn end(self) -> Result { + ser::SerializeMap::end(self) + } +} + +impl ser::SerializeStructVariant for SerializeStructVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + ser::Serialize, + { + self.map.insert(key.to_owned(), to_value(&value)?); + Ok(()) + } + + fn end(self) -> Result { + let mut object = map_with_capacity(Some(1)); + + object.insert(self.name.to_owned(), Value::Object(self.map)); + + Ok(Value::Object(object)) + } +} + +impl<'de> de::Deserializer<'de> for Value { + type Error = Error; + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + Value::Bool(v) => visitor.visit_bool(v), + Value::I64(v) => visitor.visit_i64(v), + Value::U64(v) => visitor.visit_u64(v), + Value::F64(v) => visitor.visit_f64(v), + Value::String(v) => visitor.visit_string(v), + Value::Array(v) => visitor.visit_seq(SeqDeserializer { + iter: v.into_iter(), + }), + Value::Object(v) => visitor.visit_map(MapDeserializer { + iter: v.into_iter(), + value: None, + }), + } + } + + #[inline] + fn deserialize_option(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match self { + Value::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + #[inline] + fn deserialize_enum( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let (variant, value) = match self { + Value::Object(value) => { + let mut iter = value.into_iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(de::Error::invalid_type( + de::Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(de::Error::invalid_type( + de::Unexpected::Map, + &"map with a single key", + )); + } + (variant, Some(value)) + } + Value::String(variant) => (variant, None), + val => { + return Err(de::Error::invalid_type( + val.as_unexpected(), + &"string or map", + )) + } + }; + + visitor.visit_enum(EnumDeserializer { variant, value }) + } + + #[inline] + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + serde::forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf unit unit_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +struct EnumDeserializer { + variant: String, + value: Option, +} + +impl<'de> de::EnumAccess<'de> for EnumDeserializer { + type Error = Error; + + type Variant = VariantDeserializer; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: de::DeserializeSeed<'de>, + { + let variant = de::IntoDeserializer::into_deserializer(self.variant); + let visitor = VariantDeserializer { val: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } +} + +struct VariantDeserializer { + val: Option, +} + +impl<'de, 'a> de::VariantAccess<'de> for VariantDeserializer { + type Error = Error; + + fn unit_variant(self) -> Result<()> { + match self.val { + Some(val) => de::Deserialize::deserialize(val), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: de::DeserializeSeed<'de>, + { + match self.val { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant(self, _len: usize, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let val = self.val.expect("val is missing"); + if let Value::Array(fields) = val { + visitor.visit_seq(SeqDeserializer { + iter: fields.into_iter(), + }) + } else { + Err(de::Error::invalid_type(val.as_unexpected(), &visitor)) + } + } + + fn struct_variant(self, _fields: &'static [&'static str], visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match self.val { + Some(Value::Object(fields)) => visitor.visit_map(MapDeserializer { + iter: fields.into_iter(), + value: None, + }), + Some(other) => Err(de::Error::invalid_type( + other.as_unexpected(), + &"struct variant", + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +struct SeqDeserializer { + iter: vec::IntoIter, +} + +impl<'de> de::SeqAccess<'de> for SeqDeserializer { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => Ok(Some(seed.deserialize(value)?)), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapDeserializer { + iter: MapIntoIter, + value: Option, +} + +impl<'de, 'a> de::MapAccess<'de> for MapDeserializer { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result> + where + K: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some(value); + Ok(Some(seed.deserialize(Value::String(key))?)) + } + None => Ok(None), + } + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: de::DeserializeSeed<'de>, + { + let value = self.value.take().expect("value is missing"); + seed.deserialize(value) + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +pub fn to_value(value: &T) -> Result +where + T: ser::Serialize, +{ + value.serialize(Serializer) +} + +/// Shortcut function to decode a Hjson `Value` into a `T` +pub fn from_value(value: Value) -> Result +where + T: de::DeserializeOwned, +{ + de::Deserialize::deserialize(value) +} + +/// A trait for converting values to Hjson +pub trait ToJson { + /// Converts the value of `self` to an instance of Hjson + fn to_json(&self) -> Value; +} + +impl ToJson for T +where + T: ser::Serialize, +{ + fn to_json(&self) -> Value { + to_value(&self).expect("failed to serialize") + } +} + +#[cfg(test)] +mod test { + use super::Value; + use crate::de::from_str; + + #[test] + fn number_deserialize() { + let v: Value = from_str("{\"a\":1}").unwrap(); + let vo = v.as_object().unwrap(); + assert_eq!(vo["a"].as_u64().unwrap(), 1); + + let v: Value = from_str("{\"a\":-1}").unwrap(); + let vo = v.as_object().unwrap(); + assert_eq!(vo["a"].as_i64().unwrap(), -1); + + let v: Value = from_str("{\"a\":1.1}").unwrap(); + let vo = v.as_object().unwrap(); + assert!(vo["a"].as_f64().unwrap() - 1.1 < std::f64::EPSILON); + + let v: Value = from_str("{\"a\":-1.1}").unwrap(); + let vo = v.as_object().unwrap(); + assert!(vo["a"].as_f64().unwrap() + 1.1 > -(std::f64::EPSILON)); + + let v: Value = from_str("{\"a\":1e6}").unwrap(); + let vo = v.as_object().unwrap(); + assert!(vo["a"].as_f64().unwrap() - 1e6 < std::f64::EPSILON); + + let v: Value = from_str("{\"a\":-1e6}").unwrap(); + let vo = v.as_object().unwrap(); + assert!(vo["a"].as_f64().unwrap() + 1e6 > -(std::f64::EPSILON)); + } +} diff --git a/crates/nu-json/tests/main.rs b/crates/nu-json/tests/main.rs index 92a7fd2a2d..28c264dc95 100644 --- a/crates/nu-json/tests/main.rs +++ b/crates/nu-json/tests/main.rs @@ -1,13 +1,5 @@ -<<<<<<< HEAD -extern crate nu_json; -extern crate nu_test_support; -extern crate serde; -extern crate serde_json; - -======= // FIXME: re-enable tests /* ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use nu_json::Value; use regex::Regex; use std::fs; @@ -216,8 +208,5 @@ fn test_hjson() { panic!(); } } -<<<<<<< HEAD -======= */ ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-parser/Cargo.toml b/crates/nu-parser/Cargo.toml index f8774c2f71..2f1e993cb2 100644 --- a/crates/nu-parser/Cargo.toml +++ b/crates/nu-parser/Cargo.toml @@ -1,33 +1,6 @@ [package] -<<<<<<< HEAD -authors = ["The Nu Project Contributors"] -description = "Nushell parser" -edition = "2018" -license = "MIT" name = "nu-parser" -version = "0.43.0" - -[dependencies] -bigdecimal = { package = "bigdecimal", version = "0.3.0", features = ["serde"] } -derive-new = "0.5.8" -indexmap = { version="1.6.1", features=["serde-1"] } -log = "0.4" -num-bigint = { version="0.4.3", features=["serde"] } -itertools = "0.10.0" -smart-default = "0.6.0" - -nu-errors = { version = "0.43.0", path="../nu-errors" } -nu-data = { version = "0.43.0", path="../nu-data" } -nu-path = { version = "0.43.0", path="../nu-path" } -nu-protocol = { version = "0.43.0", path="../nu-protocol" } -nu-source = { version = "0.43.0", path="../nu-source" } -nu-test-support = { version = "0.43.0", path="../nu-test-support" } - -[features] -stable = [] -======= -name = "nu-parser" -version = "0.1.0" +version = "0.59.0" edition = "2021" [dependencies] @@ -35,10 +8,9 @@ miette = "3.0.0" thiserror = "1.0.29" serde_json = "1.0" nu-path = {path = "../nu-path"} -nu-protocol = { path = "../nu-protocol"} -nu-plugin = { path = "../nu-plugin", optional = true } +nu-protocol = { path = "../nu-protocol", version = "0.59.0" } +nu-plugin = { path = "../nu-plugin", optional = true, version = "0.59.0" } log = "0.4" [features] plugin = ["nu-plugin"] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-parser/src/errors.rs b/crates/nu-parser/src/errors.rs index ddda90f023..44987e3796 100644 --- a/crates/nu-parser/src/errors.rs +++ b/crates/nu-parser/src/errors.rs @@ -1,23 +1,3 @@ -<<<<<<< HEAD -// use std::fmt::Debug; - -// A combination of an informative parse error, and what has been successfully parsed so far -// #[derive(Debug)] -// pub struct ParseError { -// /// An informative cause for this parse error -// pub cause: nu_errors::ParseError, -// // /// What has been successfully parsed, if anything -// // pub partial: Option, -// } - -// pub type ParseResult = Result>; - -// impl From> for nu_errors::ShellError { -// fn from(e: ParseError) -> Self { -// e.cause.into() -// } -// } -======= use miette::Diagnostic; use nu_protocol::{Span, Type}; use thiserror::Error; @@ -237,4 +217,3 @@ pub enum ParseError { #[diagnostic()] LabeledError(String, String, #[label("{1}")] Span), } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-parser/src/lib.rs b/crates/nu-parser/src/lib.rs index 8d37af0051..2346aaed10 100644 --- a/crates/nu-parser/src/lib.rs +++ b/crates/nu-parser/src/lib.rs @@ -1,20 +1,3 @@ -<<<<<<< HEAD -#[macro_use] -extern crate derive_new; - -mod errors; -mod flag; -mod lex; -mod parse; -mod scope; -mod shapes; - -pub use lex::lexer::{lex, parse_block, NewlineMode}; -pub use lex::tokens::{LiteBlock, LiteCommand, LiteGroup, LitePipeline}; -pub use parse::{classify_block, garbage, parse, parse_full_column_path, parse_math_expression}; -pub use scope::ParserScope; -pub use shapes::shapes; -======= mod errors; mod flatten; mod lex; @@ -34,4 +17,3 @@ pub use parser::{find_captures_in_expr, parse, parse_block, trim_quotes, Import} #[cfg(feature = "plugin")] pub use parse_keywords::parse_register; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-path/Cargo.toml b/crates/nu-path/Cargo.toml index 51099a624d..f1ca60fd7c 100644 --- a/crates/nu-path/Cargo.toml +++ b/crates/nu-path/Cargo.toml @@ -1,22 +1,11 @@ [package] authors = ["The Nu Project Contributors"] description = "Path handling library for Nushell" -<<<<<<< HEAD -edition = "2018" -license = "MIT" -name = "nu-path" -version = "0.43.0" -======= edition = "2021" license = "MIT" name = "nu-path" -version = "0.37.1" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +version = "0.59.0" [dependencies] dirs-next = "2.0.0" dunce = "1.0.1" -<<<<<<< HEAD - -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-path/README.md b/crates/nu-path/README.md new file mode 100644 index 0000000000..382fd687bd --- /dev/null +++ b/crates/nu-path/README.md @@ -0,0 +1,3 @@ +# nu-path + +This crate takes care of path handling in Nushell, such as canonicalization and component expansion, as well as other path-related utilities. diff --git a/crates/nu-path/src/dots.rs b/crates/nu-path/src/dots.rs index 169fdc2352..b6025c479c 100644 --- a/crates/nu-path/src/dots.rs +++ b/crates/nu-path/src/dots.rs @@ -19,11 +19,7 @@ fn handle_dots_push(string: &mut String, count: u8) { string.pop(); // remove last '/' } -<<<<<<< HEAD -/// Expands any occurrence of more than two dots into a sequence of ../ (or ..\ on windows), e.g., -======= /// Expands any occurence of more than two dots into a sequence of ../ (or ..\ on windows), e.g., ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce /// "..." into "../..", "...." into "../../../", etc. pub fn expand_ndots(path: impl AsRef) -> PathBuf { // Check if path is valid UTF-8 and if not, return it as it is to avoid breaking it via string diff --git a/crates/nu-path/src/expansions.rs b/crates/nu-path/src/expansions.rs index 0d70d644b8..f23b6197f1 100644 --- a/crates/nu-path/src/expansions.rs +++ b/crates/nu-path/src/expansions.rs @@ -26,32 +26,19 @@ where } } -<<<<<<< HEAD -/// Resolve all symbolic links and all components (tilde, ., .., ...+) and return the path in its -/// absolute form. -/// -/// Fails under the same conditions as -/// [std::fs::canonicalize](https://doc.rust-lang.org/std/fs/fn.canonicalize.html). -pub fn canonicalize(path: impl AsRef) -> io::Result { -======= fn canonicalize(path: impl AsRef) -> io::Result { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let path = expand_tilde(path); let path = expand_ndots(path); dunce::canonicalize(path) } -<<<<<<< HEAD -/// Same as canonicalize() but the input path is specified relative to another path -======= /// Resolve all symbolic links and all components (tilde, ., .., ...+) and return the path in its /// absolute form. /// /// Fails under the same conditions as /// [std::fs::canonicalize](https://doc.rust-lang.org/std/fs/fn.canonicalize.html). /// The input path is specified relative to another path ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub fn canonicalize_with(path: P, relative_to: Q) -> io::Result where P: AsRef, @@ -62,15 +49,12 @@ where canonicalize(path) } -<<<<<<< HEAD -======= fn expand_path(path: impl AsRef) -> PathBuf { let path = expand_tilde(path); let path = expand_ndots(path); expand_dots(path) } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce /// Resolve only path components (tilde, ., .., ...+), if possible. /// /// The function works in a "best effort" mode: It does not fail but rather returns the unexpanded @@ -79,17 +63,7 @@ fn expand_path(path: impl AsRef) -> PathBuf { /// Furthermore, unlike canonicalize(), it does not use sys calls (such as readlink). /// /// Does not convert to absolute form nor does it resolve symlinks. -<<<<<<< HEAD -pub fn expand_path(path: impl AsRef) -> PathBuf { - let path = expand_tilde(path); - let path = expand_ndots(path); - expand_dots(path) -} - -/// Same as expand_path() but the input path is specified relative to another path -======= /// The input path is specified relative to another path ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub fn expand_path_with(path: P, relative_to: Q) -> PathBuf where P: AsRef, diff --git a/crates/nu-path/src/lib.rs b/crates/nu-path/src/lib.rs index a5809d6fc7..e6fbf4e6a6 100644 --- a/crates/nu-path/src/lib.rs +++ b/crates/nu-path/src/lib.rs @@ -1,17 +1,10 @@ mod dots; mod expansions; -<<<<<<< HEAD -mod tilde; -mod util; - -pub use expansions::{canonicalize, canonicalize_with, expand_path, expand_path_with}; -======= mod helpers; mod tilde; mod util; pub use expansions::{canonicalize_with, expand_path_with}; pub use helpers::{config_dir, home_dir}; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub use tilde::expand_tilde; pub use util::trim_trailing_slash; diff --git a/crates/nu-path/src/tilde.rs b/crates/nu-path/src/tilde.rs index 6268ef2fb9..2ee1ccf456 100644 --- a/crates/nu-path/src/tilde.rs +++ b/crates/nu-path/src/tilde.rs @@ -1,10 +1,6 @@ use std::path::{Path, PathBuf}; -<<<<<<< HEAD -fn expand_tilde_with(path: impl AsRef, home: Option) -> PathBuf { -======= fn expand_tilde_with_home(path: impl AsRef, home: Option) -> PathBuf { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let path = path.as_ref(); if !path.starts_with("~") { @@ -31,11 +27,7 @@ fn expand_tilde_with_home(path: impl AsRef, home: Option) -> Path /// Expand tilde ("~") into a home directory if it is the first path component pub fn expand_tilde(path: impl AsRef) -> PathBuf { // TODO: Extend this to work with "~user" style of home paths -<<<<<<< HEAD - expand_tilde_with(path, dirs_next::home_dir()) -======= expand_tilde_with_home(path, dirs_next::home_dir()) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[cfg(test)] @@ -45,29 +37,17 @@ mod tests { fn check_expanded(s: &str) { let home = Path::new("/home"); let buf = Some(PathBuf::from(home)); -<<<<<<< HEAD - assert!(expand_tilde_with(Path::new(s), buf).starts_with(&home)); -======= assert!(expand_tilde_with_home(Path::new(s), buf).starts_with(&home)); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce // Tests the special case in expand_tilde for "/" as home let home = Path::new("/"); let buf = Some(PathBuf::from(home)); -<<<<<<< HEAD - assert!(!expand_tilde_with(Path::new(s), buf).starts_with("//")); -======= assert!(!expand_tilde_with_home(Path::new(s), buf).starts_with("//")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } fn check_not_expanded(s: &str) { let home = PathBuf::from("/home"); -<<<<<<< HEAD - let expanded = expand_tilde_with(Path::new(s), Some(home)); -======= let expanded = expand_tilde_with_home(Path::new(s), Some(home)); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert!(expanded == Path::new(s)); } diff --git a/crates/nu-path/src/util.rs b/crates/nu-path/src/util.rs new file mode 100644 index 0000000000..63351e6aef --- /dev/null +++ b/crates/nu-path/src/util.rs @@ -0,0 +1,4 @@ +/// Trim trailing path separator from a string +pub fn trim_trailing_slash(s: &str) -> &str { + s.trim_end_matches(std::path::is_separator) +} diff --git a/crates/nu-path/tests/mod.rs b/crates/nu-path/tests/mod.rs new file mode 100644 index 0000000000..83c8c0aa0a --- /dev/null +++ b/crates/nu-path/tests/mod.rs @@ -0,0 +1 @@ +mod util; diff --git a/crates/nu-path/tests/util.rs b/crates/nu-path/tests/util.rs new file mode 100644 index 0000000000..601d9dd437 --- /dev/null +++ b/crates/nu-path/tests/util.rs @@ -0,0 +1,45 @@ +use nu_path::trim_trailing_slash; +use std::path::MAIN_SEPARATOR; + +/// Helper function that joins string literals with '/' or '\', based on the host OS +fn join_path_sep(pieces: &[&str]) -> String { + let sep_string = String::from(MAIN_SEPARATOR); + pieces.join(&sep_string) +} + +#[test] +fn trims_trailing_slash_without_trailing_slash() { + let path = join_path_sep(&["some", "path"]); + + let actual = trim_trailing_slash(&path); + + assert_eq!(actual, &path) +} + +#[test] +fn trims_trailing_slash() { + let path = join_path_sep(&["some", "path", ""]); + + let actual = trim_trailing_slash(&path); + let expected = join_path_sep(&["some", "path"]); + + assert_eq!(actual, &expected) +} + +#[test] +fn trims_many_trailing_slashes() { + let path = join_path_sep(&["some", "path", "", "", "", ""]); + + let actual = trim_trailing_slash(&path); + let expected = join_path_sep(&["some", "path"]); + + assert_eq!(actual, &expected) +} + +#[test] +fn trims_trailing_slash_empty() { + let path = String::from(MAIN_SEPARATOR); + let actual = trim_trailing_slash(&path); + + assert_eq!(actual, "") +} diff --git a/crates/nu-plugin/Cargo.toml b/crates/nu-plugin/Cargo.toml index d78ca6785d..67c6a46baf 100644 --- a/crates/nu-plugin/Cargo.toml +++ b/crates/nu-plugin/Cargo.toml @@ -1,35 +1,11 @@ [package] -<<<<<<< HEAD -authors = ["The Nu Project Contributors"] -description = "Nushell Plugin" -edition = "2018" -license = "MIT" name = "nu-plugin" -version = "0.43.0" - -[lib] -doctest = false - -[dependencies] -nu-errors = { path="../nu-errors", version = "0.43.0" } -nu-protocol = { path="../nu-protocol", version = "0.43.0" } -nu-source = { path="../nu-source", version = "0.43.0" } -nu-test-support = { path="../nu-test-support", version = "0.43.0" } -nu-value-ext = { path="../nu-value-ext", version = "0.43.0" } -indexmap = { version="1.6.1", features=["serde-1"] } -serde = { version="1.0", features=["derive"] } -serde_json = "1.0" - -[build-dependencies] -======= -name = "nu-plugin" -version = "0.1.0" +version = "0.59.0" edition = "2021" [dependencies] capnp = "0.14.3" -nu-protocol = { path = "../nu-protocol" } -nu-engine = { path = "../nu-engine" } +nu-protocol = { path = "../nu-protocol", version = "0.59.0" } +nu-engine = { path = "../nu-engine", version = "0.59.0" } serde = {version = "1.0.130", features = ["derive"]} serde_json = { version = "1.0"} ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-plugin/src/lib.rs b/crates/nu-plugin/src/lib.rs index 5959de8638..de50aa1ff2 100644 --- a/crates/nu-plugin/src/lib.rs +++ b/crates/nu-plugin/src/lib.rs @@ -1,11 +1,3 @@ -<<<<<<< HEAD -pub mod jsonrpc; -mod plugin; - -pub mod test_helpers; - -pub use crate::plugin::{serve_plugin, Plugin}; -======= mod plugin; mod protocol; mod serializers; @@ -16,4 +8,3 @@ mod plugin_capnp; pub use plugin::{get_signature, serve_plugin, Plugin, PluginDeclaration}; pub use protocol::{EvaluatedCall, LabeledError}; pub use serializers::{capnp::CapnpSerializer, json::JsonSerializer, EncodingType}; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-pretty-hex/Cargo.lock b/crates/nu-pretty-hex/Cargo.lock new file mode 100644 index 0000000000..1bfc1820e4 --- /dev/null +++ b/crates/nu-pretty-hex/Cargo.lock @@ -0,0 +1,201 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "as-slice" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" +dependencies = [ + "generic-array 0.12.4", + "generic-array 0.13.3", + "generic-array 0.14.4", + "stable_deref_trait", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hash32" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422" +dependencies = [ + "as-slice", + "generic-array 0.14.4", + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "libc" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" + +[[package]] +name = "nu-ansi-term" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd69a141e8fdfa5ac882d8b816db2b9ad138ef7e3baa7cb753a9b3789aa8c7e" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-pretty-hex" +version = "0.2.1" +dependencies = [ + "heapless", + "nu-ansi-term", + "rand", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "typenum" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/crates/nu-pretty-hex/Cargo.toml b/crates/nu-pretty-hex/Cargo.toml index fddc2563e3..166df9c805 100644 --- a/crates/nu-pretty-hex/Cargo.toml +++ b/crates/nu-pretty-hex/Cargo.toml @@ -1,17 +1,10 @@ [package] authors = ["Andrei Volnin ", "The Nu Project Contributors"] description = "Pretty hex dump of bytes slice in the common style." -<<<<<<< HEAD -edition = "2018" -license = "MIT" -name = "nu-pretty-hex" -version = "0.43.0" -======= edition = "2021" license = "MIT" name = "nu-pretty-hex" -version = "0.41.0" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +version = "0.59.0" [lib] doctest = false @@ -23,11 +16,9 @@ name = "nu_pretty_hex" path = "src/main.rs" [dependencies] -<<<<<<< HEAD -nu-ansi-term = { path="../nu-ansi-term", version = "0.43.0" } -======= +#nu-ansi-term = {path = "../nu-ansi-term", version = "0.59.0" } nu-ansi-term = "0.42.0" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce + rand = "0.8.3" [dev-dependencies] diff --git a/crates/nu-pretty-hex/LICENSE b/crates/nu-pretty-hex/LICENSE new file mode 100644 index 0000000000..f70169fa2f --- /dev/null +++ b/crates/nu-pretty-hex/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Andrei Volnin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/nu-pretty-hex/README.md b/crates/nu-pretty-hex/README.md new file mode 100644 index 0000000000..7c640cc28f --- /dev/null +++ b/crates/nu-pretty-hex/README.md @@ -0,0 +1,81 @@ +# nu-pretty-hex + +An update of prett-hex to make it prettier + +[![crates.io](https://img.shields.io/crates/v/pretty-hex.svg)](https://crates.io/crates/pretty-hex) +[![docs.rs](https://docs.rs/pretty-hex/badge.svg)](https://docs.rs/pretty-hex) + +A Rust library providing pretty hex dump. + +A `simple_hex()` way renders one-line hex dump, a `pretty_hex()` way renders +columned multi-line hex dump with addressing and ASCII representation. +A `config_hex()` way renders hex dump in specified format. + +## Inspiration + +[Hexed](https://github.com/adolfohw/hexed) \ +[Hexyl](https://github.com/sharkdp/hexyl) \ +[Pretty-hex](https://github.com/wolandr/pretty-hex) + +## Example of `simple_hex()` + +```rust +use pretty_hex::*; + +let v = vec![222, 173, 190, 239, 202, 254, 32, 24]; +assert_eq!(simple_hex(&v), format!("{}", v.hex_dump())); + +println!("{}", v.hex_dump()); + +``` + +Output: + +```text +de ad be ef ca fe 20 18 +``` + +## Example of `pretty_hex()` + +```rust +use pretty_hex::*; + +let v: &[u8] = &random::<[u8;30]>(); +assert_eq!(pretty_hex(&v), format!("{:?}", v.hex_dump())); + +println!("{:?}", v.hex_dump()); +``` + +Output: + +```text +Length: 30 (0x1e) bytes +0000: 6b 4e 1a c3 af 03 d2 1e 7e 73 ba c8 bd 84 0f 83 kN......~s...... +0010: 89 d5 cf 90 23 67 4b 48 db b1 bc 35 bf ee ....#gKH...5.. +``` + +## Example of `config_hex()` + +```rust +use pretty_hex::*; + +let cfg = HexConfig {title: false, width: 8, group: 0, ..HexConfig::default() }; + +let v = &include_bytes!("data"); +assert_eq!(config_hex(&v, cfg), format!("{:?}", v.hex_conf(cfg))); + +println!("{:?}", v.hex_conf(cfg)); +``` + +Output: + +```text +0000: 6b 4e 1a c3 af 03 d2 1e kN...... +0008: 7e 73 ba c8 bd 84 0f 83 ~s...... +0010: 89 d5 cf 90 23 67 4b 48 ....#gKH +0018: db b1 bc 35 bf ee ...5.. +``` + +--- + +Inspired by [haskell's pretty-hex](https://hackage.haskell.org/package/pretty-hex-1.0). diff --git a/crates/nu-pretty-hex/src/lib.rs b/crates/nu-pretty-hex/src/lib.rs new file mode 100644 index 0000000000..d34542a7ee --- /dev/null +++ b/crates/nu-pretty-hex/src/lib.rs @@ -0,0 +1,66 @@ +// #![no_std] + +//! A Rust library providing pretty hex dump. +//! +//! A `simple_hex()` way renders one-line hex dump, and a `pretty_hex()` way renders +//! columned multi-line hex dump with addressing and ASCII representation. +//! A `config_hex()` way renders hex dump in specified format. +//! +//! ## Example of `simple_hex()` +//! ``` +//! use pretty_hex::*; +//! +//! let v = vec![222, 173, 190, 239, 202, 254, 32, 24]; +//! # #[cfg(feature = "alloc")] +//! assert_eq!(simple_hex(&v), format!("{}", v.hex_dump())); +//! +//! println!("{}", v.hex_dump()); +//! ``` +//! Output: +//! +//! ```text +//! de ad be ef ca fe 20 18 +//! ``` +//! ## Example of `pretty_hex()` +//! ``` +//! use pretty_hex::*; +//! +//! let v = &include_bytes!("../tests/data"); +//! # #[cfg(feature = "alloc")] +//! assert_eq!(pretty_hex(&v), format!("{:?}", v.hex_dump())); +//! +//! println!("{:?}", v.hex_dump()); +//! ``` +//! Output: +//! +//! ```text +//! Length: 30 (0x1e) bytes +//! 0000: 6b 4e 1a c3 af 03 d2 1e 7e 73 ba c8 bd 84 0f 83 kN......~s...... +//! 0010: 89 d5 cf 90 23 67 4b 48 db b1 bc 35 bf ee ....#gKH...5.. +//! ``` +//! ## Example of `config_hex()` +//! ``` +//! use pretty_hex::*; +//! +//! let cfg = HexConfig {title: false, width: 8, group: 0, ..HexConfig::default() }; +//! +//! let v = &include_bytes!("../tests/data"); +//! # #[cfg(feature = "alloc")] +//! assert_eq!(config_hex(&v, cfg), format!("{:?}", v.hex_conf(cfg))); +//! +//! println!("{:?}", v.hex_conf(cfg)); +//! ``` +//! Output: +//! +//! ```text +//! 0000: 6b 4e 1a c3 af 03 d2 1e kN...... +//! 0008: 7e 73 ba c8 bd 84 0f 83 ~s...... +//! 0010: 89 d5 cf 90 23 67 4b 48 ....#gKH +//! 0018: db b1 bc 35 bf ee ...5.. +//! ``` + +#[cfg(feature = "alloc")] +extern crate alloc; + +mod pretty_hex; +pub use pretty_hex::*; diff --git a/crates/nu-pretty-hex/src/main.rs b/crates/nu-pretty-hex/src/main.rs index 1863770b98..b7e1dacf81 100644 --- a/crates/nu-pretty-hex/src/main.rs +++ b/crates/nu-pretty-hex/src/main.rs @@ -7,10 +7,7 @@ fn main() { width: 16, group: 4, chunk: 1, -<<<<<<< HEAD -======= address_offset: 0, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce skip: Some(10), // length: Some(5), // length: None, diff --git a/crates/nu-pretty-hex/src/pretty_hex.rs b/crates/nu-pretty-hex/src/pretty_hex.rs index 0cfb2a7b2c..b3066c0b92 100644 --- a/crates/nu-pretty-hex/src/pretty_hex.rs +++ b/crates/nu-pretty-hex/src/pretty_hex.rs @@ -57,11 +57,8 @@ pub struct HexConfig { pub group: usize, /// Source bytes per chunk (word). 0 for single word. pub chunk: usize, -<<<<<<< HEAD -======= /// Offset to start counting addresses from pub address_offset: usize, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce /// Bytes from 0 to skip pub skip: Option, /// Length to return @@ -78,10 +75,7 @@ impl Default for HexConfig { width: 16, group: 4, chunk: 1, -<<<<<<< HEAD -======= address_offset: 0, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce skip: None, length: None, } @@ -173,11 +167,8 @@ where let skip = cfg.skip.unwrap_or(0); -<<<<<<< HEAD -======= let address_offset = cfg.address_offset; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let source_part_vec: Vec = source .as_ref() .iter() @@ -219,19 +210,11 @@ where writer, "{}{:08x}{}: ", style.prefix(), -<<<<<<< HEAD - i * cfg.width + skip, - style.suffix() - )?; - } else { - write!(writer, "{:08x}: ", i * cfg.width + skip,)?; -======= i * cfg.width + skip + address_offset, style.suffix() )?; } else { write!(writer, "{:08x}: ", i * cfg.width + skip + address_offset,)?; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } for (i, x) in row.as_ref().iter().enumerate() { diff --git a/crates/nu-pretty-hex/tests/256.txt b/crates/nu-pretty-hex/tests/256.txt new file mode 100644 index 0000000000..0e08e874f7 --- /dev/null +++ b/crates/nu-pretty-hex/tests/256.txt @@ -0,0 +1,17 @@ +Length: 256 (0x100) bytes +0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................ +0010: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ................ +0020: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f !"#$%&'()*+,-./ +0030: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>? +0040: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO +0050: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\]^_ +0060: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno +0070: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~. +0080: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f ................ +0090: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f ................ +00a0: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af ................ +00b0: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf ................ +00c0: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf ................ +00d0: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df ................ +00e0: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef ................ +00f0: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff ................ \ No newline at end of file diff --git a/crates/nu-pretty-hex/tests/data b/crates/nu-pretty-hex/tests/data new file mode 100644 index 0000000000..998d80f715 --- /dev/null +++ b/crates/nu-pretty-hex/tests/data @@ -0,0 +1 @@ +kNΓ―~sΊΘ½„ƒ‰Υϐ#gKHΫ±Ό5Ώξ \ No newline at end of file diff --git a/crates/nu-pretty-hex/tests/tests.rs b/crates/nu-pretty-hex/tests/tests.rs new file mode 100644 index 0000000000..a147c496ce --- /dev/null +++ b/crates/nu-pretty-hex/tests/tests.rs @@ -0,0 +1,175 @@ +// #![no_std] + +#[cfg(feature = "alloc")] +extern crate alloc; +extern crate nu_pretty_hex; + +#[cfg(feature = "alloc")] +use alloc::{format, string::String, vec, vec::Vec}; +use nu_pretty_hex::*; + +#[cfg(feature = "alloc")] +#[test] +fn test_simple() { + let bytes: Vec = (0..16).collect(); + let expected = "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f"; + assert_eq!(expected, simple_hex(&bytes)); + assert_eq!(expected, bytes.hex_dump().to_string()); + assert_eq!(simple_hex(&bytes), config_hex(&bytes, HexConfig::simple())); + + let mut have = String::new(); + simple_hex_write(&mut have, &bytes).unwrap(); + assert_eq!(expected, have); + + let str = "string"; + let string: String = String::from("string"); + let slice: &[u8] = &[0x73, 0x74, 0x72, 0x69, 0x6e, 0x67]; + assert_eq!(simple_hex(&str), "73 74 72 69 6e 67"); + assert_eq!(simple_hex(&str), simple_hex(&string)); + assert_eq!(simple_hex(&str), simple_hex(&slice)); + + assert!(simple_hex(&vec![]).is_empty()); +} + +#[cfg(feature = "alloc")] +#[test] +fn test_pretty() { + let bytes: Vec = (0..256).map(|x| x as u8).collect(); + let want = include_str!("256.txt"); + + let mut hex = String::new(); + pretty_hex_write(&mut hex, &bytes).unwrap(); + assert_eq!(want, hex); + assert_eq!(want, format!("{:?}", bytes.hex_dump())); + assert_eq!(want, pretty_hex(&bytes)); + assert_eq!(want, config_hex(&bytes, HexConfig::default())); + + assert_eq!("Length: 0 (0x0) bytes\n", pretty_hex(&vec![])); +} + +#[cfg(feature = "alloc")] +#[test] +fn test_config() { + let cfg = HexConfig { + title: false, + ascii: false, + width: 0, + group: 0, + chunk: 0, + }; + assert!(config_hex(&vec![], cfg).is_empty()); + assert_eq!("2425262728", config_hex(&"$%&'(", cfg)); + + let v = include_bytes!("data"); + let cfg = HexConfig { + title: false, + group: 8, + ..HexConfig::default() + }; + let hex = "0000: 6b 4e 1a c3 af 03 d2 1e 7e 73 ba c8 bd 84 0f 83 kN......~s......\n\ + 0010: 89 d5 cf 90 23 67 4b 48 db b1 bc 35 bf ee ....#gKH...5.."; + assert_eq!(hex, config_hex(&v, cfg)); + assert_eq!(hex, format!("{:?}", v.hex_conf(cfg))); + let mut str = String::new(); + hex_write(&mut str, v, cfg).unwrap(); + assert_eq!(hex, str); + + assert_eq!( + config_hex( + &v, + HexConfig { + ascii: false, + ..cfg + } + ), + "0000: 6b 4e 1a c3 af 03 d2 1e 7e 73 ba c8 bd 84 0f 83\n\ + 0010: 89 d5 cf 90 23 67 4b 48 db b1 bc 35 bf ee" + ); + + assert_eq!( + config_hex( + &v, + HexConfig { + ascii: false, + group: 4, + chunk: 2, + ..cfg + } + ), + "0000: 6b4e 1ac3 af03 d21e 7e73 bac8 bd84 0f83\n\ + 0010: 89d5 cf90 2367 4b48 dbb1 bc35 bfee" + ); + + let v: Vec = (0..21).collect(); + let want = r##"Length: 21 (0x15) bytes +0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................ +0010: 10 11 12 13 14 ....."##; + assert_eq!(want, pretty_hex(&v)); + + let v: Vec = (0..13).collect(); + assert_eq!( + config_hex( + &v, + HexConfig { + title: false, + ascii: true, + width: 11, + group: 2, + chunk: 3 + } + ), + "0000: 000102 030405 060708 090a ...........\n\ + 000b: 0b0c .." + ); + + let v: Vec = (0..19).collect(); + assert_eq!( + config_hex( + &v, + HexConfig { + title: false, + ascii: true, + width: 16, + group: 3, + chunk: 3 + } + ), + "0000: 000102 030405 060708 090a0b 0c0d0e 0f ................\n\ + 0010: 101112 ..." + ); + + let cfg = HexConfig { + title: false, + group: 0, + ..HexConfig::default() + }; + assert_eq!( + format!("{:?}", v.hex_conf(cfg)), + "0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................\n\ + 0010: 10 11 12 ..." + ); + assert_eq!( + v.hex_conf(cfg).to_string(), + "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12" + ); +} + +// This test case checks that hex_write works even without the alloc crate. +// Decorators to this function like simple_hex_write or PrettyHex::hex_dump() +// will be tested when the alloc feature is selected because it feels quite +// cumbersome to set up these tests without the comodity from `alloc`. +#[test] +fn test_hex_write_with_simple_config() { + let config = HexConfig::simple(); + let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + let expected = + core::str::from_utf8(b"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f").unwrap(); + // let expected = + // "\u{1b}[38;5;242m00\u{1b}[0m \u{1b}[1;35m01\u{1b}[0m \u{1b}[1;35m02\u{1b}[0m \u{1b}[1;"; + let mut buffer = heapless::Vec::::new(); + + hex_write(&mut buffer, &bytes, config, None).unwrap(); + + let have = core::str::from_utf8(&buffer).unwrap(); + assert_eq!(expected, have); +} diff --git a/crates/nu-protocol/Cargo.toml b/crates/nu-protocol/Cargo.toml index 70d4194fd5..e28f06ef9c 100644 --- a/crates/nu-protocol/Cargo.toml +++ b/crates/nu-protocol/Cargo.toml @@ -1,45 +1,6 @@ [package] -<<<<<<< HEAD -authors = ["The Nu Project Contributors"] -description = "Core values and protocols for Nushell" -edition = "2018" -license = "MIT" name = "nu-protocol" -version = "0.43.0" - -[lib] -doctest = false - -[dependencies] -bigdecimal = { package = "bigdecimal", version = "0.3.0", features = ["serde"] } -byte-unit = "4.0.9" -chrono = { version="0.4.19", features=["serde"] } -chrono-humanize = "0.2.1" -derive-new = "0.5.8" -getset = "0.1.1" -indexmap = { version="1.6.1", features=["serde-1"] } -log = "0.4.14" -nu-errors = { path="../nu-errors", version = "0.43.0" } -nu-source = { path="../nu-source", version = "0.43.0" } -num-bigint = { version = "0.4.3", features = ["serde"] } -num-integer = "0.1.44" -num-traits = "0.2.14" -serde = { version="1.0", features=["derive"] } -serde_bytes = "0.11.5" - -[dependencies.polars] -version = "0.17.0" -optional = true -default-features = false -features = ["docs", "zip_with", "csv-file", "temporal", "performant", "pretty_fmt", "dtype-slim", "serde", "rows", "strings", "checked_arithmetic", "object", "dtype-date", "dtype-datetime", "dtype-time"] - -[features] -dataframe = ["polars"] - -[build-dependencies] -======= -name = "nu-protocol" -version = "0.1.0" +version = "0.59.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -54,7 +15,7 @@ chrono-humanize = "0.2.1" byte-unit = "4.0.9" im = "15.0.0" serde_json = { version = "1.0", optional = true } -nu-json = { path = "../nu-json" } +nu-json = { path = "../nu-json", version = "0.59.0" } typetag = "0.1.8" num-format = "0.4.0" sys-locale = "0.1.0" @@ -64,4 +25,3 @@ plugin = ["serde_json"] [dev-dependencies] serde_json = "1.0" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-protocol/src/lib.rs b/crates/nu-protocol/src/lib.rs index 8f01ee83e0..60e45b2bb5 100644 --- a/crates/nu-protocol/src/lib.rs +++ b/crates/nu-protocol/src/lib.rs @@ -1,40 +1,3 @@ -<<<<<<< HEAD -#[macro_use] -mod macros; - -mod call_info; -pub mod config_path; -pub mod hir; -mod maybe_owned; -mod registry; -mod return_value; -mod signature; -mod syntax_shape; -mod type_name; -mod type_shape; -pub mod value; - -#[cfg(feature = "dataframe")] -pub mod dataframe; - -pub use crate::call_info::{CallInfo, EvaluatedArgs}; -pub use crate::config_path::ConfigPath; -pub use crate::maybe_owned::MaybeOwned; -pub use crate::registry::{SignatureRegistry, VariableRegistry}; -pub use crate::return_value::{CommandAction, ReturnSuccess, ReturnValue}; -pub use crate::signature::{NamedType, PositionalType, Signature}; -pub use crate::syntax_shape::SyntaxShape; -pub use crate::type_name::{PrettyType, ShellTypeName, SpannedTypeName}; -pub use crate::type_shape::{Row as RowType, Type}; -pub use crate::value::column_path::{ColumnPath, PathMember, UnspannedPathMember}; -pub use crate::value::dict::{Dictionary, TaggedDictBuilder}; -pub use crate::value::did_you_mean::did_you_mean; -pub use crate::value::primitive::Primitive; -pub use crate::value::primitive::{format_date, format_duration, format_primitive}; -pub use crate::value::range::{Range, RangeInclusion}; -pub use crate::value::value_structure::{ValueResource, ValueStructure}; -pub use crate::value::{merge_descriptors, UntaggedValue, Value}; -======= pub mod ast; mod config; pub mod engine; @@ -67,4 +30,3 @@ pub use syntax_shape::*; pub use ty::*; pub use value::CustomValue; pub use value::*; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs index 43f75cafd7..b02d4f3814 100644 --- a/crates/nu-protocol/src/shell_error.rs +++ b/crates/nu-protocol/src/shell_error.rs @@ -36,7 +36,7 @@ pub enum ShellError { #[error("Type mismatch")] #[diagnostic(code(nu::shell::type_mismatch), url(docsrs))] - TypeMismatch(String, #[label = "{0}"] Span), + TypeMismatch(String, #[label = "needs {0}"] Span), #[error("Unsupported operator: {0}.")] #[diagnostic(code(nu::shell::unsupported_operator), url(docsrs))] diff --git a/crates/nu-protocol/src/signature.rs b/crates/nu-protocol/src/signature.rs index c4996325ce..6ea31f6b4c 100644 --- a/crates/nu-protocol/src/signature.rs +++ b/crates/nu-protocol/src/signature.rs @@ -1,163 +1,3 @@ -<<<<<<< HEAD -use crate::syntax_shape::SyntaxShape; -use crate::type_shape::Type; -use indexmap::IndexMap; -use nu_source::{DbgDocBldr, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource}; -use serde::{Deserialize, Serialize}; - -/// The types of named parameter that a command can have -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -pub enum NamedType { - /// A flag without any associated argument. eg) `foo --bar, foo -b` - Switch(Option), - /// A mandatory flag, with associated argument. eg) `foo --required xyz, foo -r xyz` - Mandatory(Option, SyntaxShape), - /// An optional flag, with associated argument. eg) `foo --optional abc, foo -o abc` - Optional(Option, SyntaxShape), -} - -impl NamedType { - pub fn get_short(&self) -> Option { - match self { - NamedType::Switch(s) => *s, - NamedType::Mandatory(s, _) => *s, - NamedType::Optional(s, _) => *s, - } - } - - pub fn get_type_description(&self) -> (String, String, String) { - let empty_string = ("".to_string(), "".to_string(), "".to_string()); - match self { - NamedType::Switch(f) => match f { - Some(flag) => ("switch_flag".to_string(), flag.to_string(), "".to_string()), - None => empty_string, - }, - NamedType::Mandatory(f, shape) => match f { - Some(flag) => ( - "mandatory_flag".to_string(), - flag.to_string(), - shape.syntax_shape_name().to_string(), - ), - None => empty_string, - }, - NamedType::Optional(f, shape) => match f { - Some(flag) => ( - "optional_flag".to_string(), - flag.to_string(), - shape.syntax_shape_name().to_string(), - ), - None => empty_string, - }, - } - } -} - -/// The type of positional arguments -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub enum PositionalType { - /// A mandatory positional argument with the expected shape of the value - Mandatory(String, SyntaxShape), - /// An optional positional argument with the expected shape of the value - Optional(String, SyntaxShape), -} - -impl PrettyDebug for PositionalType { - /// Prepare the PositionalType for pretty-printing - fn pretty(&self) -> DebugDocBuilder { - match self { - PositionalType::Mandatory(string, shape) => { - DbgDocBldr::description(string) - + DbgDocBldr::delimit("(", shape.pretty(), ")") - .into_kind() - .group() - } - PositionalType::Optional(string, shape) => { - DbgDocBldr::description(string) - + DbgDocBldr::operator("?") - + DbgDocBldr::delimit("(", shape.pretty(), ")") - .into_kind() - .group() - } - } - } -} - -impl PositionalType { - /// Helper to create a mandatory positional argument type - pub fn mandatory(name: &str, ty: SyntaxShape) -> PositionalType { - PositionalType::Mandatory(name.to_string(), ty) - } - - /// Helper to create a mandatory positional argument with an "any" type - pub fn mandatory_any(name: &str) -> PositionalType { - PositionalType::Mandatory(name.to_string(), SyntaxShape::Any) - } - - /// Helper to create a mandatory positional argument with a block type - pub fn mandatory_block(name: &str) -> PositionalType { - PositionalType::Mandatory(name.to_string(), SyntaxShape::Block) - } - - /// Helper to create a optional positional argument type - pub fn optional(name: &str, ty: SyntaxShape) -> PositionalType { - PositionalType::Optional(name.to_string(), ty) - } - - /// Helper to create a optional positional argument with an "any" type - pub fn optional_any(name: &str) -> PositionalType { - PositionalType::Optional(name.to_string(), SyntaxShape::Any) - } - - /// Gets the name of the positional argument - pub fn name(&self) -> &str { - match self { - PositionalType::Mandatory(s, _) => s, - PositionalType::Optional(s, _) => s, - } - } - - /// Gets the expected type of a positional argument - pub fn syntax_type(&self) -> SyntaxShape { - match *self { - PositionalType::Mandatory(_, t) => t, - PositionalType::Optional(_, t) => t, - } - } - - pub fn get_type_description(&self) -> (String, String) { - match &self { - PositionalType::Mandatory(c, s) => (c.to_string(), s.syntax_shape_name().to_string()), - PositionalType::Optional(c, s) => (c.to_string(), s.syntax_shape_name().to_string()), - } - } -} - -type Description = String; - -/// The full signature of a command. All commands have a signature similar to a function signature. -/// Commands will use this information to register themselves with Nu's core engine so that the command -/// can be invoked, help can be displayed, and calls to the command can be error-checked. -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Signature { - /// The name of the command. Used when calling the command - pub name: String, - /// Usage instructions about the command - pub usage: String, - /// Longer or more verbose usage statement - pub extra_usage: String, - /// The list of positional arguments, both required and optional, and their corresponding types and help text - pub positional: Vec<(PositionalType, Description)>, - /// After the positional arguments, a catch-all for the rest of the arguments that might follow, their type, and help text - pub rest_positional: Option<(String, SyntaxShape, Description)>, - /// The named flags with corresponding type and help text - pub named: IndexMap, - /// The type of values being sent out from the command into the pipeline, if any - pub yields: Option, - /// The type of values being read in from the pipeline into the command, if any - pub input: Option, - /// If the command is expected to filter data, or to consume it (as a sink) - pub is_filter: bool, -======= use serde::Deserialize; use serde::Serialize; @@ -256,19 +96,14 @@ pub struct Signature { pub creates_scope: bool, // Signature category used to classify commands stored in the list of declarations pub category: Category, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } impl PartialEq for Signature { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.usage == other.usage -<<<<<<< HEAD - && self.positional == other.positional -======= && self.required_positional == other.required_positional && self.optional_positional == other.optional_positional ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce && self.rest_positional == other.rest_positional && self.is_filter == other.is_filter } @@ -277,61 +112,6 @@ impl PartialEq for Signature { impl Eq for Signature {} impl Signature { -<<<<<<< HEAD - pub fn shift_positional(&mut self) { - self.positional = Vec::from(&self.positional[1..]); - } - - pub fn remove_named(&mut self, name: &str) { - self.named.remove(name); - } - - pub fn allowed(&self) -> Vec { - let mut allowed = indexmap::IndexSet::new(); - - for (name, (t, _)) in &self.named { - if let Some(c) = t.get_short() { - allowed.insert(format!("-{}", c)); - } - allowed.insert(format!("--{}", name)); - } - - for (ty, _) in &self.positional { - let shape = ty.syntax_type(); - allowed.insert(shape.display()); - } - - if let Some((_, shape, _)) = &self.rest_positional { - allowed.insert(shape.display()); - } - - allowed.into_iter().collect() - } -} - -impl PrettyDebugWithSource for Signature { - /// Prepare a Signature for pretty-printing - fn pretty_debug(&self, source: &str) -> DebugDocBuilder { - DbgDocBldr::typed( - "signature", - DbgDocBldr::description(&self.name) - + DbgDocBldr::preceded( - DbgDocBldr::space(), - DbgDocBldr::intersperse( - self.positional - .iter() - .map(|(ty, _)| ty.pretty_debug(source)), - DbgDocBldr::space(), - ), - ), - ) - } -} - -impl Signature { - /// Create a new command signature with the given name - pub fn new(name: impl Into) -> Signature { -======= pub fn new(name: impl Into) -> Signature { // default help flag let flag = Flag { @@ -343,23 +123,10 @@ impl Signature { var_id: None, }; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce Signature { name: name.into(), usage: String::new(), extra_usage: String::new(), -<<<<<<< HEAD - positional: vec![], - rest_positional: None, - named: indexmap::indexmap! {"help".into() => (NamedType::Switch(Some('h')), "Display this help message".into())}, - is_filter: false, - yields: None, - input: None, - } - } - - /// Create a new signature -======= required_positional: vec![], optional_positional: vec![], rest_positional: None, @@ -369,7 +136,6 @@ impl Signature { category: Category::Default, } } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub fn build(name: impl Into) -> Signature { Signature::new(name.into()) } @@ -384,15 +150,6 @@ impl Signature { pub fn required( mut self, name: impl Into, -<<<<<<< HEAD - ty: impl Into, - desc: impl Into, - ) -> Signature { - self.positional.push(( - PositionalType::Mandatory(name.into(), ty.into()), - desc.into(), - )); -======= shape: impl Into, desc: impl Into, ) -> Signature { @@ -402,24 +159,10 @@ impl Signature { shape: shape.into(), var_id: None, }); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce self } -<<<<<<< HEAD - /// Add an optional positional argument to the signature - pub fn optional( - mut self, - name: impl Into, - ty: impl Into, - desc: impl Into, - ) -> Signature { - self.positional.push(( - PositionalType::Optional(name.into(), ty.into()), - desc.into(), - )); -======= /// Add a required positional argument to the signature pub fn optional( mut self, @@ -449,7 +192,6 @@ impl Signature { shape: shape.into(), var_id: None, }); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce self } @@ -458,20 +200,6 @@ impl Signature { pub fn named( mut self, name: impl Into, -<<<<<<< HEAD - ty: impl Into, - desc: impl Into, - short: Option, - ) -> Signature { - let s = short.map(|c| { - debug_assert!(!self.get_shorts().contains(&c)); - c - }); - self.named.insert( - name.into(), - (NamedType::Optional(s, ty.into()), desc.into()), - ); -======= shape: impl Into, desc: impl Into, short: Option, @@ -486,7 +214,6 @@ impl Signature { desc: desc.into(), var_id: None, }); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce self } @@ -495,22 +222,6 @@ impl Signature { pub fn required_named( mut self, name: impl Into, -<<<<<<< HEAD - ty: impl Into, - desc: impl Into, - short: Option, - ) -> Signature { - let s = short.map(|c| { - debug_assert!(!self.get_shorts().contains(&c)); - c - }); - - self.named.insert( - name.into(), - (NamedType::Mandatory(s, ty.into()), desc.into()), - ); - -======= shape: impl Into, desc: impl Into, short: Option, @@ -526,7 +237,6 @@ impl Signature { var_id: None, }); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce self } @@ -537,8 +247,6 @@ impl Signature { desc: impl Into, short: Option, ) -> Signature { -<<<<<<< HEAD -======= let (name, s) = self.check_names(name, short); self.named.push(Flag { @@ -610,7 +318,6 @@ impl Signature { /// Checks if short or long are already present /// Panics if one of them is found fn check_names(&self, name: impl Into, short: Option) -> (String, Option) { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let s = short.map(|c| { debug_assert!( !self.get_shorts().contains(&c), @@ -619,11 +326,6 @@ impl Signature { c }); -<<<<<<< HEAD - self.named - .insert(name.into(), (NamedType::Switch(s), desc.into())); - self -======= let name = { let name: String = name.into(); debug_assert!( @@ -707,7 +409,6 @@ impl Signature { } } None ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } /// Set the filter flag for the signature @@ -716,42 +417,6 @@ impl Signature { self } -<<<<<<< HEAD - /// Set the type for the "rest" of the positional arguments - /// Note: Not naming the field in your struct holding the rest values "rest", can - /// cause errors when deserializing - pub fn rest( - mut self, - name: impl Into, - ty: SyntaxShape, - desc: impl Into, - ) -> Signature { - self.rest_positional = Some((name.into(), ty, desc.into())); - self - } - - /// Add a type for the output of the command to the signature - pub fn yields(mut self, ty: Type) -> Signature { - self.yields = Some(ty); - self - } - - /// Add a type for the input of the command to the signature - pub fn input(mut self, ty: Type) -> Signature { - self.input = Some(ty); - self - } - - /// Get list of the short-hand flags - pub fn get_shorts(&self) -> Vec { - let mut shorts = Vec::new(); - for (_, (t, _)) in &self.named { - if let Some(c) = t.get_short() { - shorts.push(c); - } - } - shorts -======= /// Create a placeholder implementation of Command as a way to predeclare a definition's /// signature so other definitions can see it. This placeholder is later replaced with the /// full definition in a second pass of the parser. @@ -847,6 +512,5 @@ impl Command for BlockCommand { fn get_block_id(&self) -> Option { Some(self.block_id) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } diff --git a/crates/nu-protocol/src/syntax_shape.rs b/crates/nu-protocol/src/syntax_shape.rs index 112042dc18..90b0dd201f 100644 --- a/crates/nu-protocol/src/syntax_shape.rs +++ b/crates/nu-protocol/src/syntax_shape.rs @@ -1,65 +1,3 @@ -<<<<<<< HEAD -use nu_source::{DbgDocBldr, DebugDocBuilder, PrettyDebug}; -use serde::{Deserialize, Serialize}; - -/// The syntactic shapes that values must match to be passed into a command. You can think of this as the type-checking that occurs when you call a function. -#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] -pub enum SyntaxShape { - /// Any syntactic form is allowed - Any, - /// Strings and string-like bare words are allowed - String, - /// A dotted path to navigate the table - ColumnPath, - /// A dotted path to navigate the table (including variable) - FullColumnPath, - /// Only a numeric (integer or decimal) value is allowed - Number, - /// A range is allowed (eg, `1..3`) - Range, - /// Only an integer value is allowed - Int, - /// A filepath is allowed - FilePath, - /// A glob pattern is allowed, eg `foo*` - GlobPattern, - /// A block is allowed, eg `{start this thing}` - Block, - /// A table is allowed, eg `[first second]` - Table, - /// A filesize value is allowed, eg `10kb` - Filesize, - /// A duration value is allowed, eg `19day` - Duration, - /// An operator - Operator, - /// A math expression which expands shorthand forms on the lefthand side, eg `foo > 1` - /// The shorthand allows us to more easily reach columns inside of the row being passed in - RowCondition, - /// A general math expression, eg the `1 + 2` of `= 1 + 2` - MathExpression, -} - -impl SyntaxShape { - pub fn syntax_shape_name(&self) -> &str { - match self { - SyntaxShape::Any => "any", - SyntaxShape::String => "string", - SyntaxShape::FullColumnPath => "column path (with variable)", - SyntaxShape::ColumnPath => "column path", - SyntaxShape::Number => "number", - SyntaxShape::Range => "range", - SyntaxShape::Int => "integer", - SyntaxShape::FilePath => "file path", - SyntaxShape::GlobPattern => "pattern", - SyntaxShape::Block => "block", - SyntaxShape::Table => "table", - SyntaxShape::Duration => "duration", - SyntaxShape::Filesize => "filesize", - SyntaxShape::Operator => "operator", - SyntaxShape::RowCondition => "condition", - SyntaxShape::MathExpression => "math expression", -======= use std::fmt::Display; use serde::{Deserialize, Serialize}; @@ -181,17 +119,10 @@ impl SyntaxShape { SyntaxShape::Table => Type::List(Box::new(Type::Unknown)), // FIXME: Tables should have better types SyntaxShape::VarWithOptType => Type::Unknown, SyntaxShape::Variable => Type::Unknown, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } } -<<<<<<< HEAD -impl PrettyDebug for SyntaxShape { - /// Prepare SyntaxShape for pretty-printing - fn pretty(&self) -> DebugDocBuilder { - DbgDocBldr::kind(self.syntax_shape_name().to_string()) -======= impl Display for SyntaxShape { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -224,6 +155,5 @@ impl Display for SyntaxShape { SyntaxShape::Boolean => write!(f, "bool"), SyntaxShape::Custom(x, _) => write!(f, "custom<{}>", x), } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } diff --git a/crates/nu-protocol/src/value/range.rs b/crates/nu-protocol/src/value/range.rs index 4f404f411e..bff06d1387 100644 --- a/crates/nu-protocol/src/value/range.rs +++ b/crates/nu-protocol/src/value/range.rs @@ -1,157 +1,3 @@ -<<<<<<< HEAD -use crate::value::Primitive; -use derive_new::new; -use nu_errors::ShellError; -use nu_source::{DbgDocBldr, DebugDocBuilder, Spanned}; -use serde::{Deserialize, Serialize}; - -/// The two types of ways to include a range end. Inclusive means to include the value (eg 1..3 inclusive would include the 3 value). -/// Exclusive excludes the value (eg 1..3 exclusive does not include 3 value) -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] -pub enum RangeInclusion { - Inclusive, - Exclusive, -} - -impl RangeInclusion { - /// Get a RangeInclusion left bracket ready for pretty printing - pub fn debug_left_bracket(self) -> DebugDocBuilder { - DbgDocBldr::delimiter(match self { - RangeInclusion::Exclusive => "(", - RangeInclusion::Inclusive => "[", - }) - } - - /// Get a RangeInclusion right bracket ready for pretty printing - pub fn debug_right_bracket(self) -> DebugDocBuilder { - DbgDocBldr::delimiter(match self { - RangeInclusion::Exclusive => ")", - RangeInclusion::Inclusive => "]", - }) - } -} - -/// The range definition, holding the starting and end point of the range -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize, new)] -pub struct Range { - pub from: (Spanned, RangeInclusion), - pub to: (Spanned, RangeInclusion), -} - -impl Range { - pub fn min_u64(&self) -> Result { - let (from, range_incl) = &self.from; - - let minval = if let Primitive::Nothing = from.item { - u64::MIN - } else { - from.item.as_u64(from.span)? - }; - - match range_incl { - RangeInclusion::Inclusive => Ok(minval), - RangeInclusion::Exclusive => Ok(minval.saturating_add(1)), - } - } - - pub fn max_u64(&self) -> Result { - let (to, range_incl) = &self.to; - - let maxval = if let Primitive::Nothing = to.item { - u64::MAX - } else { - to.item.as_u64(to.span)? - }; - - match range_incl { - RangeInclusion::Inclusive => Ok(maxval), - RangeInclusion::Exclusive => Ok(maxval.saturating_sub(1)), - } - } - - pub fn min_i64(&self) -> Result { - let (from, range_incl) = &self.from; - - let minval = if let Primitive::Nothing = from.item { - 0 - } else { - from.item.as_i64(from.span)? - }; - - match range_incl { - RangeInclusion::Inclusive => Ok(minval), - RangeInclusion::Exclusive => Ok(minval.saturating_add(1)), - } - } - - pub fn max_i64(&self) -> Result { - let (to, range_incl) = &self.to; - - let maxval = if let Primitive::Nothing = to.item { - i64::MAX - } else { - to.item.as_i64(to.span)? - }; - - match range_incl { - RangeInclusion::Inclusive => Ok(maxval), - RangeInclusion::Exclusive => Ok(maxval.saturating_sub(1)), - } - } - - pub fn min_usize(&self) -> Result { - let (from, range_incl) = &self.from; - - let minval = if let Primitive::Nothing = from.item { - usize::MIN - } else { - from.item.as_usize(from.span)? - }; - - match range_incl { - RangeInclusion::Inclusive => Ok(minval), - RangeInclusion::Exclusive => Ok(minval.saturating_add(1)), - } - } - - pub fn max_usize(&self) -> Result { - let (to, range_incl) = &self.to; - - let maxval = if let Primitive::Nothing = to.item { - usize::MAX - } else { - to.item.as_usize(to.span)? - }; - - match range_incl { - RangeInclusion::Inclusive => Ok(maxval), - RangeInclusion::Exclusive => Ok(maxval.saturating_sub(1)), - } - } - - pub fn min_f64(&self) -> Result { - let from = &self.from.0; - - if let Primitive::Nothing = from.item { - Ok(f64::MIN) - } else { - Ok(from.item.as_f64(from.span)?) - } - - // How would inclusive vs. exclusive range work here? - } - - pub fn max_f64(&self) -> Result { - let to = &self.to.0; - - if let Primitive::Nothing = to.item { - Ok(f64::MAX) - } else { - Ok(to.item.as_f64(to.span)?) - } - - // How would inclusive vs. exclusive range work here? -======= use serde::{Deserialize, Serialize}; use std::cmp::Ordering; @@ -370,6 +216,5 @@ impl Iterator for RangeIterator { } else { None } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } diff --git a/crates/nu-system/Cargo.lock b/crates/nu-system/Cargo.lock index 47bce2f73b..c11185da77 100644 --- a/crates/nu-system/Cargo.lock +++ b/crates/nu-system/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "nu-system" -version = "0.1.0" +version = "0.59.0" dependencies = [ "errno", "libproc", diff --git a/crates/nu-system/Cargo.toml b/crates/nu-system/Cargo.toml index 9dd4278e1a..3d086a1e00 100644 --- a/crates/nu-system/Cargo.toml +++ b/crates/nu-system/Cargo.toml @@ -2,7 +2,7 @@ authors = ["The Nu Project Contributors", "procs creators"] description = "Nushell system querying" name = "nu-system" -version = "0.60.0" +version = "0.59.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/nu-table/.gitignore b/crates/nu-table/.gitignore new file mode 100644 index 0000000000..4c234e523b --- /dev/null +++ b/crates/nu-table/.gitignore @@ -0,0 +1,22 @@ +/target +/scratch +**/*.rs.bk +history.txt +tests/fixtures/nuplayground +crates/*/target + +# Debian/Ubuntu +debian/.debhelper/ +debian/debhelper-build-stamp +debian/files +debian/nu.substvars +debian/nu/ + +# macOS junk +.DS_Store + +# JetBrains' IDE items +.idea/* + +# VSCode's IDE items +.vscode/* diff --git a/crates/nu-table/Cargo.toml b/crates/nu-table/Cargo.toml index d3a198ca4b..f61e2e890a 100644 --- a/crates/nu-table/Cargo.toml +++ b/crates/nu-table/Cargo.toml @@ -1,17 +1,10 @@ [package] authors = ["The Nu Project Contributors"] description = "Nushell table printing" -<<<<<<< HEAD -edition = "2018" -license = "MIT" -name = "nu-table" -version = "0.43.0" -======= edition = "2021" license = "MIT" name = "nu-table" -version = "0.36.0" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +version = "0.59.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [[bin]] @@ -19,20 +12,11 @@ name = "table" path = "src/main.rs" [dependencies] -<<<<<<< HEAD -atty = "0.2.14" -nu-ansi-term = { version = "0.43.0", path="../nu-ansi-term" } - -regex = "1.4" -strip-ansi-escapes = "0.1.1" -unicode-width = "0.1.8" -======= -# nu-ansi-term = { path = "../nu-ansi-term" } +# nu-ansi-term = { path = "../nu-ansi-term", version = "0.59.0" } nu-ansi-term = "0.42.0" -nu-protocol = { path = "../nu-protocol"} +nu-protocol = { path = "../nu-protocol", version = "0.59.0" } regex = "1.4" unicode-width = "0.1.8" strip-ansi-escapes = "0.1.1" ansi-cut = "0.2.0" atty = "0.2.14" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-table/src/lib.rs b/crates/nu-table/src/lib.rs new file mode 100644 index 0000000000..661d7ddde7 --- /dev/null +++ b/crates/nu-table/src/lib.rs @@ -0,0 +1,5 @@ +mod table; +mod wrap; + +pub use table::{draw_table, StyledString, Table, TextStyle, Theme}; +pub use wrap::Alignment; diff --git a/crates/nu-table/src/main.rs b/crates/nu-table/src/main.rs index ccc23a5ea2..75401b888b 100644 --- a/crates/nu-table/src/main.rs +++ b/crates/nu-table/src/main.rs @@ -1,7 +1,4 @@ -<<<<<<< HEAD -======= use nu_protocol::Config; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use nu_table::{draw_table, StyledString, Table, TextStyle, Theme}; use std::collections::HashMap; @@ -29,29 +26,12 @@ fn main() { let table = Table::new(headers, vec![rows; 3], Theme::rounded()); // FIXME: Config isn't available from here so just put these here to compile let color_hm: HashMap = HashMap::new(); -<<<<<<< HEAD - // Capture the table as a string - let output_table = draw_table(&table, width, &color_hm); - - if atty::is(atty::Stream::Stdout) { - // Draw the table with ansi colors - println!("{}", output_table) - } else { - // Draw the table without ansi colors - if let Ok(bytes) = strip_ansi_escapes::strip(&output_table) { - println!("{}", String::from_utf8_lossy(&bytes)) - } else { - println!("{}", output_table) - } - } -======= // get the default config let config = Config::default(); // Capture the table as a string let output_table = draw_table(&table, width, &color_hm, &config); // Draw the table println!("{}", output_table) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } fn make_table_data() -> (Vec<&'static str>, Vec<&'static str>) { diff --git a/crates/nu-table/src/table.rs b/crates/nu-table/src/table.rs index e64c201b31..b4c324374c 100644 --- a/crates/nu-table/src/table.rs +++ b/crates/nu-table/src/table.rs @@ -1,9 +1,6 @@ use crate::wrap::{column_width, split_sublines, wrap, Alignment, Subline, WrappedCell}; use nu_ansi_term::{Color, Style}; -<<<<<<< HEAD -======= use nu_protocol::{Config, FooterMode}; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use std::collections::HashMap; use std::fmt::Write; @@ -244,13 +241,10 @@ impl TextStyle { .bold(Some(true)) } -<<<<<<< HEAD -======= pub fn default_field() -> TextStyle { TextStyle::new().fg(Color::Green).bold(Some(true)) } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub fn with_attributes(bo: bool, al: Alignment, co: Color) -> TextStyle { TextStyle::new().alignment(al).fg(co).bold(Some(bo)) } @@ -618,26 +612,15 @@ impl Table { } #[derive(Debug)] -<<<<<<< HEAD -pub struct ProcessedTable<'a> { - pub headers: Vec>, - pub data: Vec>>, -======= pub struct ProcessedTable { pub headers: Vec, pub data: Vec>, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub theme: Theme, } #[derive(Debug)] -<<<<<<< HEAD -pub struct ProcessedCell<'a> { - pub contents: Vec>>, -======= pub struct ProcessedCell { pub contents: Vec>, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub style: TextStyle, } @@ -647,10 +630,7 @@ pub struct WrappedTable { pub headers: Vec, pub data: Vec>, pub theme: Theme, -<<<<<<< HEAD -======= pub footer: Vec, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } impl WrappedTable { @@ -662,11 +642,7 @@ impl WrappedTable { let column_count = self.column_widths.len(); let mut output = String::new(); let sep_color = color_hm -<<<<<<< HEAD - .get("separator_color") -======= .get("separator") ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce .unwrap_or(&Style::default()) .to_owned(); @@ -715,10 +691,7 @@ impl WrappedTable { ); } } -<<<<<<< HEAD -======= output.push('\n'); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } SeparatorPosition::Middle => { for column in self.column_widths.iter().enumerate() { @@ -762,10 +735,7 @@ impl WrappedTable { .push_str(&sep_color.paint(&self.theme.center.to_string()).to_string()); } } -<<<<<<< HEAD -======= output.push('\n'); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } SeparatorPosition::Bottom => { for column in self.column_widths.iter().enumerate() { @@ -812,10 +782,6 @@ impl WrappedTable { } } } -<<<<<<< HEAD - output.push('\n'); -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce output } @@ -825,11 +791,7 @@ impl WrappedTable { color_hm: &HashMap, ) -> String { let sep_color = color_hm -<<<<<<< HEAD - .get("separator_color") -======= .get("separator") ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce .unwrap_or(&Style::default()) .to_owned(); @@ -913,24 +875,11 @@ impl WrappedTable { break; } -<<<<<<< HEAD - writeln!(&mut total_output, "{}", output).unwrap(); -======= writeln!(&mut total_output, "{}", output).expect("writing should be done to buffer"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } total_output } -<<<<<<< HEAD - fn print_table(&self, color_hm: &HashMap) -> String { - let mut output = String::new(); - - #[cfg(windows)] - { - let _ = nu_ansi_term::enable_ansi_support(); - } -======= fn print_table(&self, color_hm: &HashMap, config: &Config) -> String { let mut output = String::new(); @@ -939,24 +888,17 @@ impl WrappedTable { // { // let _ = nu_ansi_term::enable_ansi_support(); // } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce if self.data.is_empty() { return output; } -<<<<<<< HEAD -======= // The top border ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce if self.theme.print_top_border { output.push_str(&self.print_separator(SeparatorPosition::Top, color_hm)); } -<<<<<<< HEAD -======= // The header ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let skip_headers = (self.headers.len() == 2 && self.headers[1].max_width == 0) || (self.headers.len() == 1 && self.headers[0].max_width == 0); @@ -964,13 +906,8 @@ impl WrappedTable { output.push_str(&self.print_cell_contents(&self.headers, color_hm)); } -<<<<<<< HEAD - let mut first_row = true; - -======= // The middle section let mut first_row = true; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce for row in &self.data { if !first_row { if self.theme.separate_rows { @@ -987,8 +924,6 @@ impl WrappedTable { output.push_str(&self.print_cell_contents(row, color_hm)); } -<<<<<<< HEAD -======= match config.footer_mode { FooterMode::Always => { if self.theme.separate_header && !self.headers.is_empty() && !skip_headers { @@ -1014,32 +949,21 @@ impl WrappedTable { } // The table finish ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce if self.theme.print_bottom_border { output.push_str(&self.print_separator(SeparatorPosition::Bottom, color_hm)); } -<<<<<<< HEAD - if atty::is(atty::Stream::Stdout) { - // Draw the table with ansi colors - output - } else { -======= // the atty is for when people do ls from vim, there should be no coloring there if !config.use_ansi_coloring || !atty::is(atty::Stream::Stdout) { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce // Draw the table without ansi colors if let Ok(bytes) = strip_ansi_escapes::strip(&output) { String::from_utf8_lossy(&bytes).to_string() } else { output } -<<<<<<< HEAD -======= } else { // Draw the table with ansi colors output ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } } @@ -1112,11 +1036,7 @@ pub fn maybe_truncate_columns(termwidth: usize, processed_table: &mut ProcessedT processed_table.headers.push(ProcessedCell { contents: vec![vec![Subline { -<<<<<<< HEAD - subline: "...", -======= subline: "...".to_string(), ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce width: 3, }]], style: TextStyle::basic_center(), @@ -1125,11 +1045,7 @@ pub fn maybe_truncate_columns(termwidth: usize, processed_table: &mut ProcessedT for entry in processed_table.data.iter_mut() { entry.push(ProcessedCell { contents: vec![vec![Subline { -<<<<<<< HEAD - subline: "...", -======= subline: "...".to_string(), ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce width: 3, }]], style: TextStyle::basic_center(), @@ -1138,12 +1054,6 @@ pub fn maybe_truncate_columns(termwidth: usize, processed_table: &mut ProcessedT } } -<<<<<<< HEAD -pub fn draw_table(table: &Table, termwidth: usize, color_hm: &HashMap) -> String { - // Remove the edges, if used - let termwidth = if table.theme.print_left_border && table.theme.print_right_border { - termwidth - 2 -======= pub fn draw_table( table: &Table, termwidth: usize, @@ -1153,7 +1063,6 @@ pub fn draw_table( // Remove the edges, if used let termwidth = if table.theme.print_left_border && table.theme.print_right_border { termwidth - 3 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } else if table.theme.print_left_border || table.theme.print_right_border { termwidth - 1 } else { @@ -1210,11 +1119,7 @@ pub fn draw_table( &re_trailing, ); -<<<<<<< HEAD - wrapped_table.print_table(color_hm) -======= wrapped_table.print_table(color_hm, config) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } fn wrap_cells( @@ -1292,8 +1197,6 @@ fn wrap_cells( output_data.push(output_row); } -<<<<<<< HEAD -======= let mut footer = vec![ WrappedCell { lines: vec![], @@ -1306,16 +1209,12 @@ fn wrap_cells( ]; footer.clone_from_slice(&output_headers[..]); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce WrappedTable { column_widths, headers: output_headers, data: output_data, theme: processed_table.theme, -<<<<<<< HEAD -======= footer, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } diff --git a/crates/nu-table/src/wrap.rs b/crates/nu-table/src/wrap.rs index 0938babff5..bd0e95275a 100644 --- a/crates/nu-table/src/wrap.rs +++ b/crates/nu-table/src/wrap.rs @@ -1,16 +1,9 @@ use crate::table::TextStyle; -<<<<<<< HEAD -use nu_ansi_term::Style; -use std::collections::HashMap; -use std::{fmt::Display, iter::Iterator}; -use unicode_width::UnicodeWidthStr; -======= use ansi_cut::AnsiCut; use nu_ansi_term::Style; use std::collections::HashMap; use std::{fmt::Display, iter::Iterator}; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[derive(Debug, Clone, Copy)] pub enum Alignment { @@ -20,42 +13,24 @@ pub enum Alignment { } #[derive(Debug)] -<<<<<<< HEAD -pub struct Subline<'a> { - pub subline: &'a str, -======= pub struct Subline { pub subline: String, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub width: usize, } #[derive(Debug)] -<<<<<<< HEAD -pub struct Line<'a> { - pub sublines: Vec>, - pub width: usize, -} - -#[derive(Debug)] -======= pub struct Line { pub sublines: Vec, pub width: usize, } #[derive(Debug, Clone)] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub struct WrappedLine { pub line: String, pub width: usize, } -<<<<<<< HEAD -#[derive(Debug)] -======= #[derive(Debug, Clone)] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub struct WrappedCell { pub lines: Vec, pub max_width: usize, @@ -63,11 +38,7 @@ pub struct WrappedCell { pub style: TextStyle, } -<<<<<<< HEAD -impl<'a> Display for Line<'a> { -======= impl Display for Line { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut first = true; for subline in &self.sublines { @@ -82,8 +53,6 @@ impl Display for Line { } } -<<<<<<< HEAD -======= fn strip_ansi(astring: &str) -> String { if let Ok(bytes) = strip_ansi_escapes::strip(astring) { String::from_utf8_lossy(&bytes).to_string() @@ -120,27 +89,18 @@ fn unicode_width_strip_ansi(astring: &str) -> usize { // UnicodeWidthStr::width(&no_fe0f[..]) // } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub fn split_sublines(input: &str) -> Vec> { input .split_terminator('\n') .map(|line| { line.split_terminator(' ') .map(|x| Subline { -<<<<<<< HEAD - subline: x, -======= subline: x.to_string(), ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce width: { // We've tried UnicodeWidthStr::width(x), UnicodeSegmentation::graphemes(x, true).count() // and x.chars().count() with all types of combinations. Currently, it appears that // getting the max of char count and Unicode width seems to produce the best layout. // However, it's not perfect. -<<<<<<< HEAD - let c = x.chars().count(); - let u = UnicodeWidthStr::width(x); -======= // let c = x.chars().count(); // let u = UnicodeWidthStr::width(x); // std::cmp::min(c, u) @@ -151,7 +111,6 @@ pub fn split_sublines(input: &str) -> Vec> { let c = strip_ansi(x).chars().count(); let u = unicode_width_strip_ansi(x); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce std::cmp::max(c, u) }, }) @@ -187,31 +146,18 @@ pub fn column_width(input: &[Vec]) -> usize { } fn split_word(cell_width: usize, word: &str) -> Vec { -<<<<<<< HEAD - use unicode_width::UnicodeWidthChar; - -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let mut output = vec![]; let mut current_width = 0; let mut start_index = 0; let mut end_index; -<<<<<<< HEAD - for c in word.char_indices() { -======= let word_no_ansi = strip_ansi(word); for c in word_no_ansi.char_indices() { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce if let Some(width) = c.1.width() { end_index = c.0; if current_width + width > cell_width { output.push(Subline { -<<<<<<< HEAD - subline: &word[start_index..end_index], -======= subline: word.cut(start_index..end_index), ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce width: current_width, }); @@ -223,15 +169,9 @@ fn split_word(cell_width: usize, word: &str) -> Vec { } } -<<<<<<< HEAD - if start_index != word.len() { - output.push(Subline { - subline: &word[start_index..], -======= if start_index != word_no_ansi.len() { output.push(Subline { subline: word.cut(start_index..), ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce width: current_width, }); } @@ -239,15 +179,9 @@ fn split_word(cell_width: usize, word: &str) -> Vec { output } -<<<<<<< HEAD -pub fn wrap<'a>( - cell_width: usize, - mut input: impl Iterator>, -======= pub fn wrap( cell_width: usize, mut input: impl Iterator, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce color_hm: &HashMap, re_leading: ®ex::Regex, re_trailing: ®ex::Regex, @@ -275,11 +209,7 @@ pub fn wrap( // If this is a really long single word, we need to split the word if current_line.len() == 1 && current_width > cell_width { max_width = cell_width; -<<<<<<< HEAD - let sublines = split_word(cell_width, current_line[0].subline); -======= let sublines = split_word(cell_width, ¤t_line[0].subline); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce for subline in sublines { let width = subline.width; lines.push(Line { @@ -314,11 +244,7 @@ pub fn wrap( None => { if current_width > cell_width { // We need to break up the last word -<<<<<<< HEAD - let sublines = split_word(cell_width, current_line[0].subline); -======= let sublines = split_word(cell_width, ¤t_line[0].subline); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce for subline in sublines { let width = subline.width; lines.push(Line { @@ -353,11 +279,7 @@ pub fn wrap( first = false; current_line_width = subline.width; } -<<<<<<< HEAD - current_line.push_str(subline.subline); -======= current_line.push_str(&subline.subline); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } if current_line_width > current_max { diff --git a/crates/nu-term-grid/Cargo.toml b/crates/nu-term-grid/Cargo.toml index c524284fe1..ff69236dd5 100644 --- a/crates/nu-term-grid/Cargo.toml +++ b/crates/nu-term-grid/Cargo.toml @@ -4,7 +4,7 @@ description = "Nushell grid printing" edition = "2021" license = "MIT" name = "nu-term-grid" -version = "0.36.0" +version = "0.59.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [[bin]] diff --git a/crates/nu-test-support/Cargo.toml b/crates/nu-test-support/Cargo.toml index 6871226158..a029293cf5 100644 --- a/crates/nu-test-support/Cargo.toml +++ b/crates/nu-test-support/Cargo.toml @@ -4,21 +4,14 @@ description = "Support for writing Nushell tests" edition = "2018" license = "MIT" name = "nu-test-support" -version = "0.43.0" +version = "0.59.0" [lib] doctest = false [dependencies] -<<<<<<< HEAD -nu-errors = { version = "0.43.0", path="../nu-errors" } -nu-path = { version = "0.43.0", path="../nu-path" } -nu-protocol = { path="../nu-protocol", version = "0.43.0" } -nu-source = { path="../nu-source", version = "0.43.0" } -======= -nu-path = { path="../nu-path" } -nu-protocol = { path="../nu-protocol" } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +nu-path = { path="../nu-path", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } bigdecimal = { package = "bigdecimal", version = "0.3.0", features = ["serde"] } chrono = "0.4.19" diff --git a/crates/nu-test-support/src/commands.rs b/crates/nu-test-support/src/commands.rs index 569bd822b0..d59c2f3dad 100644 --- a/crates/nu-test-support/src/commands.rs +++ b/crates/nu-test-support/src/commands.rs @@ -1,51 +1,3 @@ -<<<<<<< HEAD -use nu_protocol::hir::{Expression, ExternalArgs, ExternalCommand, SpannedExpression}; -use nu_source::{Span, SpannedItem, Tag}; - -pub struct ExternalBuilder { - name: String, - args: Vec, -} - -impl ExternalBuilder { - pub fn for_name(name: &str) -> ExternalBuilder { - ExternalBuilder { - name: name.to_string(), - args: vec![], - } - } - - pub fn arg(&mut self, value: &str) -> &mut Self { - self.args.push(value.to_string()); - self - } - - pub fn build(&mut self) -> ExternalCommand { - let mut path = crate::fs::binaries(); - path.push(&self.name); - - let name = path.to_string_lossy().to_string().spanned(Span::unknown()); - - let args = self - .args - .iter() - .map(|arg| SpannedExpression { - expr: Expression::string(arg.to_string()), - span: Span::unknown(), - }) - .collect::>(); - - ExternalCommand { - name: name.to_string(), - name_tag: Tag::unknown(), - args: ExternalArgs { - list: args, - span: name.span, - }, - } - } -} -======= // use nu_protocol::{ // ast::{Expr, Expression}, // Span, Spanned, Type, @@ -99,4 +51,3 @@ impl ExternalBuilder { // } // } // } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu-test-support/src/fs.rs b/crates/nu-test-support/src/fs.rs new file mode 100644 index 0000000000..bf7d87df77 --- /dev/null +++ b/crates/nu-test-support/src/fs.rs @@ -0,0 +1,277 @@ +use std::io::Read; +use std::ops::Div; +use std::path::{Path, PathBuf}; + +pub struct AbsoluteFile { + inner: PathBuf, +} + +impl AbsoluteFile { + pub fn new(path: impl AsRef) -> AbsoluteFile { + let path = path.as_ref(); + + if !path.is_absolute() { + panic!( + "AbsoluteFile::new must take an absolute path :: {}", + path.display() + ) + } else if path.is_dir() { + // At the moment, this is not an invariant, but rather a way to catch bugs + // in tests. + panic!( + "AbsoluteFile::new must not take a directory :: {}", + path.display() + ) + } else { + AbsoluteFile { + inner: path.to_path_buf(), + } + } + } + + pub fn dir(&self) -> AbsolutePath { + AbsolutePath::new(if let Some(parent) = self.inner.parent() { + parent + } else { + unreachable!("Internal error: could not get parent in dir") + }) + } +} + +impl From for PathBuf { + fn from(file: AbsoluteFile) -> Self { + file.inner + } +} + +pub struct AbsolutePath { + pub inner: PathBuf, +} + +impl AbsolutePath { + pub fn new(path: impl AsRef) -> AbsolutePath { + let path = path.as_ref(); + + if path.is_absolute() { + AbsolutePath { + inner: path.to_path_buf(), + } + } else { + panic!("AbsolutePath::new must take an absolute path") + } + } +} + +impl Div<&str> for &AbsolutePath { + type Output = AbsolutePath; + + fn div(self, rhs: &str) -> Self::Output { + let parts = rhs.split('/'); + let mut result = self.inner.clone(); + + for part in parts { + result = result.join(part); + } + + AbsolutePath::new(result) + } +} + +impl AsRef for AbsolutePath { + fn as_ref(&self) -> &Path { + self.inner.as_path() + } +} + +pub struct RelativePath { + inner: PathBuf, +} + +impl RelativePath { + pub fn new(path: impl Into) -> RelativePath { + let path = path.into(); + + if path.is_relative() { + RelativePath { inner: path } + } else { + panic!("RelativePath::new must take a relative path") + } + } +} + +impl> Div for &RelativePath { + type Output = RelativePath; + + fn div(self, rhs: T) -> Self::Output { + let parts = rhs.as_ref().split('/'); + let mut result = self.inner.clone(); + + for part in parts { + result = result.join(part); + } + + RelativePath::new(result) + } +} +pub trait DisplayPath { + fn display_path(&self) -> String; +} + +impl DisplayPath for AbsolutePath { + fn display_path(&self) -> String { + self.inner.display().to_string() + } +} + +impl DisplayPath for PathBuf { + fn display_path(&self) -> String { + self.display().to_string() + } +} + +impl DisplayPath for str { + fn display_path(&self) -> String { + self.to_string() + } +} + +impl DisplayPath for &str { + fn display_path(&self) -> String { + (*self).to_string() + } +} + +impl DisplayPath for String { + fn display_path(&self) -> String { + self.clone() + } +} + +impl DisplayPath for &String { + fn display_path(&self) -> String { + (*self).to_string() + } +} +pub enum Stub<'a> { + FileWithContent(&'a str, &'a str), + FileWithContentToBeTrimmed(&'a str, &'a str), + EmptyFile(&'a str), +} + +pub fn file_contents(full_path: impl AsRef) -> String { + let mut file = std::fs::File::open(full_path.as_ref()).expect("can not open file"); + let mut contents = String::new(); + file.read_to_string(&mut contents) + .expect("can not read file"); + contents +} + +pub fn file_contents_binary(full_path: impl AsRef) -> Vec { + let mut file = std::fs::File::open(full_path.as_ref()).expect("can not open file"); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).expect("can not read file"); + contents +} + +pub fn line_ending() -> String { + #[cfg(windows)] + { + String::from("\r\n") + } + + #[cfg(not(windows))] + { + String::from("\n") + } +} + +pub fn delete_file_at(full_path: impl AsRef) { + let full_path = full_path.as_ref(); + + if full_path.exists() { + std::fs::remove_file(full_path).expect("can not delete file"); + } +} + +pub fn create_file_at(full_path: impl AsRef) -> Result<(), std::io::Error> { + let full_path = full_path.as_ref(); + + if full_path.parent().is_some() { + panic!("path exists"); + } + + std::fs::write(full_path, b"fake data") +} + +pub fn copy_file_to(source: &str, destination: &str) { + std::fs::copy(source, destination).expect("can not copy file"); +} + +pub fn files_exist_at(files: Vec>, path: impl AsRef) -> bool { + files.iter().all(|f| { + let mut loc = PathBuf::from(path.as_ref()); + loc.push(f); + loc.exists() + }) +} + +pub fn delete_directory_at(full_path: &str) { + std::fs::remove_dir_all(PathBuf::from(full_path)).expect("can not remove directory"); +} + +pub fn executable_path() -> PathBuf { + let mut path = binaries(); + path.push("nu"); + path +} + +pub fn root() -> PathBuf { + let manifest_dir = if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") { + PathBuf::from(manifest_dir) + } else { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + }; + + let test_path = manifest_dir.join("Cargo.lock"); + if test_path.exists() { + manifest_dir + } else { + manifest_dir + .parent() + .expect("Couldn't find the debug binaries directory") + .parent() + .expect("Couldn't find the debug binaries directory") + .to_path_buf() + } +} + +pub fn binaries() -> PathBuf { + let mut build_type = "debug"; + if !cfg!(debug_assertions) { + build_type = "release" + } + + std::env::var("CARGO_TARGET_DIR") + .ok() + .map(|target_dir| PathBuf::from(target_dir).join(&build_type)) + .unwrap_or_else(|| root().join(format!("target/{}", &build_type))) +} + +pub fn fixtures() -> PathBuf { + root().join("tests/fixtures") +} + +pub fn assets() -> PathBuf { + root().join("tests/assets") +} + +pub fn in_directory(str: impl AsRef) -> String { + let path = str.as_ref(); + let path = if path.is_relative() { + root().join(path) + } else { + path.to_path_buf() + }; + + path.display().to_string() +} diff --git a/crates/nu-test-support/src/lib.rs b/crates/nu-test-support/src/lib.rs index f75185e85d..7075ae0cae 100644 --- a/crates/nu-test-support/src/lib.rs +++ b/crates/nu-test-support/src/lib.rs @@ -2,10 +2,6 @@ pub mod commands; pub mod fs; pub mod macros; pub mod playground; -<<<<<<< HEAD -pub mod value; -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub struct Outcome { pub out: String, @@ -60,11 +56,7 @@ mod tests { open los_tres_amigos.txt | from-csv | get rusty_luck -<<<<<<< HEAD - | str to-int -======= | into int ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce | math sum | echo "$it" "#, @@ -72,11 +64,7 @@ mod tests { assert_eq!( actual, -<<<<<<< HEAD - r#"open los_tres_amigos.txt | from-csv | get rusty_luck | str to-int | math sum | echo "$it""# -======= r#"open los_tres_amigos.txt | from-csv | get rusty_luck | into int | math sum | echo "$it""# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); } } diff --git a/crates/nu-test-support/src/macros.rs b/crates/nu-test-support/src/macros.rs index 02b30ae624..f692754411 100644 --- a/crates/nu-test-support/src/macros.rs +++ b/crates/nu-test-support/src/macros.rs @@ -15,28 +15,12 @@ macro_rules! nu { }}; ($cwd:expr, $path:expr) => {{ -<<<<<<< HEAD -======= pub use itertools::Itertools; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub use std::error::Error; pub use std::io::prelude::*; pub use std::process::{Command, Stdio}; pub use $crate::NATIVE_PATH_ENV_VAR; -<<<<<<< HEAD - let commands = &*format!( - " - cd \"{}\" - {} - exit", - $crate::fs::in_directory($cwd), - $crate::fs::DisplayPath::display_path(&$path) - ); - - let test_bins = $crate::fs::binaries(); - let test_bins = nu_path::canonicalize(&test_bins).unwrap_or_else(|e| { -======= // let commands = &*format!( // " // cd \"{}\" @@ -50,7 +34,6 @@ macro_rules! nu { let cwd = std::env::current_dir().expect("Could not get current working directory."); let test_bins = nu_path::canonicalize_with(&test_bins, cwd).unwrap_or_else(|e| { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce panic!( "Couldn't canonicalize dummy binaries path {}: {:?}", test_bins.display(), @@ -61,11 +44,8 @@ macro_rules! nu { let mut paths = $crate::shell_os_paths(); paths.insert(0, test_bins); -<<<<<<< HEAD -======= let path = $path.lines().collect::>().join("; "); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let paths_joined = match std::env::join_paths(paths) { Ok(all) => all, Err(_) => panic!("Couldn't join paths for PATH var."), @@ -73,14 +53,6 @@ macro_rules! nu { let mut process = match Command::new($crate::fs::executable_path()) .env(NATIVE_PATH_ENV_VAR, paths_joined) -<<<<<<< HEAD - .arg("--skip-plugins") - .arg("--no-history") - .arg("--config-file") - .arg($crate::fs::DisplayPath::display_path(&$crate::fs::fixtures().join("playground/config/default.toml"))) - .stdout(Stdio::piped()) - .stdin(Stdio::piped()) -======= // .arg("--skip-plugins") // .arg("--no-history") // .arg("--config-file") @@ -88,20 +60,10 @@ macro_rules! nu { .arg(format!("-c 'cd {}; {}'", $crate::fs::in_directory($cwd), $crate::fs::DisplayPath::display_path(&path))) .stdout(Stdio::piped()) // .stdin(Stdio::piped()) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce .stderr(Stdio::piped()) .spawn() { Ok(child) => child, -<<<<<<< HEAD - Err(why) => panic!("Can't run test {}", why.to_string()), - }; - - let stdin = process.stdin.as_mut().expect("couldn't open stdin"); - stdin - .write_all(commands.as_bytes()) - .expect("couldn't write to stdin"); -======= Err(why) => panic!("Can't run test {:?} {}", $crate::fs::executable_path(), why.to_string()), }; @@ -109,7 +71,6 @@ macro_rules! nu { // stdin // .write_all(b"exit\n") // .expect("couldn't write to stdin"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let output = process .wait_with_output() diff --git a/crates/nu-test-support/src/playground.rs b/crates/nu-test-support/src/playground.rs new file mode 100644 index 0000000000..caeb4f26cf --- /dev/null +++ b/crates/nu-test-support/src/playground.rs @@ -0,0 +1,12 @@ +mod director; +pub mod matchers; +pub mod nu_process; +mod play; + +#[cfg(test)] +mod tests; + +pub use director::Director; +pub use matchers::says; +pub use nu_process::{Executable, NuProcess, NuResult, Outcome}; +pub use play::{Dirs, EnvironmentVariable, Playground}; diff --git a/crates/nu-test-support/src/playground/director.rs b/crates/nu-test-support/src/playground/director.rs index 75f82454cb..de06bb3204 100644 --- a/crates/nu-test-support/src/playground/director.rs +++ b/crates/nu-test-support/src/playground/director.rs @@ -84,21 +84,10 @@ impl Director { impl Executable for Director { fn execute(&mut self) -> NuResult { -<<<<<<< HEAD - use std::io::Write; -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use std::process::Stdio; match self.executable() { Some(binary) => { -<<<<<<< HEAD - let mut process = match binary - .construct() - .stdout(Stdio::piped()) - .stdin(Stdio::piped()) - .stderr(Stdio::piped()) -======= let mut commands = String::new(); if let Some(pipelines) = &self.pipeline { for pipeline in pipelines { @@ -115,28 +104,12 @@ impl Executable for Director { // .stdin(Stdio::piped()) .stderr(Stdio::piped()) .arg(format!("-c '{}'", commands)) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce .spawn() { Ok(child) => child, Err(why) => panic!("Can't run test {}", why), }; -<<<<<<< HEAD - if let Some(pipelines) = &self.pipeline { - let child = process.stdin.as_mut().expect("Failed to open stdin"); - - for pipeline in pipelines { - child - .write_all(format!("{}\n", pipeline).as_bytes()) - .expect("Could not write to"); - } - - child.write_all(b"exit\n").expect("Could not write to"); - } - -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce process .wait_with_output() .map_err(|_| { diff --git a/crates/nu-test-support/src/playground/matchers.rs b/crates/nu-test-support/src/playground/matchers.rs new file mode 100644 index 0000000000..7c36489e2d --- /dev/null +++ b/crates/nu-test-support/src/playground/matchers.rs @@ -0,0 +1,105 @@ +use hamcrest2::core::{MatchResult, Matcher}; +use std::fmt; +use std::str; + +use super::nu_process::Outcome; +use super::{Director, Executable}; + +#[derive(Clone)] +pub struct Play { + stdout_expectation: Option, +} + +impl fmt::Display for Play { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "play") + } +} + +impl fmt::Debug for Play { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "play") + } +} + +pub fn says() -> Play { + Play { + stdout_expectation: None, + } +} + +trait CheckerMatchers { + fn output(&self, actual: &Outcome) -> MatchResult; + fn std(&self, actual: &[u8], expected: Option<&String>, description: &str) -> MatchResult; + fn stdout(&self, actual: &Outcome) -> MatchResult; +} + +impl CheckerMatchers for Play { + fn output(&self, actual: &Outcome) -> MatchResult { + self.stdout(actual) + } + + fn stdout(&self, actual: &Outcome) -> MatchResult { + self.std(&actual.out, self.stdout_expectation.as_ref(), "stdout") + } + + fn std(&self, actual: &[u8], expected: Option<&String>, description: &str) -> MatchResult { + let out = match expected { + Some(out) => out, + None => return Ok(()), + }; + let actual = match str::from_utf8(actual) { + Err(..) => return Err(format!("{} was not utf8 encoded", description)), + Ok(actual) => actual, + }; + + if actual != *out { + return Err(format!( + "not equal:\n actual: {}\n expected: {}\n\n", + actual, out + )); + } + + Ok(()) + } +} + +impl Matcher for Play { + fn matches(&self, output: Outcome) -> MatchResult { + self.output(&output) + } +} + +impl Matcher for Play { + fn matches(&self, mut director: Director) -> MatchResult { + self.matches(&mut director) + } +} + +impl<'a> Matcher<&'a mut Director> for Play { + fn matches(&self, director: &'a mut Director) -> MatchResult { + if director.executable().is_none() { + return Err(format!("no such process {}", director)); + } + + let res = director.execute(); + + match res { + Ok(out) => self.output(&out), + Err(err) => { + if let Some(out) = &err.output { + return self.output(out); + } + + Err(format!("could not exec process {}: {:?}", director, err)) + } + } + } +} + +impl Play { + pub fn stdout(mut self, expected: &str) -> Self { + self.stdout_expectation = Some(expected.to_string()); + self + } +} diff --git a/crates/nu-test-support/src/playground/nu_process.rs b/crates/nu-test-support/src/playground/nu_process.rs new file mode 100644 index 0000000000..ffb3271ac4 --- /dev/null +++ b/crates/nu-test-support/src/playground/nu_process.rs @@ -0,0 +1,104 @@ +use super::EnvironmentVariable; +use crate::fs::{binaries as test_bins_path, executable_path}; +use std::ffi::{OsStr, OsString}; +use std::fmt; +use std::path::Path; +use std::process::{Command, ExitStatus}; + +pub trait Executable { + fn execute(&mut self) -> NuResult; +} + +#[derive(Clone, Debug)] +pub struct Outcome { + pub out: Vec, + pub err: Vec, +} + +impl Outcome { + pub fn new(out: &[u8], err: &[u8]) -> Outcome { + Outcome { + out: out.to_vec(), + err: err.to_vec(), + } + } +} + +pub type NuResult = Result; + +#[derive(Debug)] +pub struct NuError { + pub desc: String, + pub exit: Option, + pub output: Option, +} + +#[derive(Clone, Debug, Default)] +pub struct NuProcess { + pub arguments: Vec, + pub environment_vars: Vec, + pub cwd: Option, +} + +impl fmt::Display for NuProcess { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "`nu")?; + + for arg in &self.arguments { + write!(f, " {}", arg.to_string_lossy())?; + } + + write!(f, "`") + } +} + +impl NuProcess { + pub fn arg>(&mut self, arg: T) -> &mut Self { + self.arguments.push(arg.as_ref().to_os_string()); + self + } + + pub fn args>(&mut self, arguments: &[T]) -> &mut NuProcess { + self.arguments + .extend(arguments.iter().map(|t| t.as_ref().to_os_string())); + self + } + + pub fn cwd>(&mut self, path: T) -> &mut NuProcess { + self.cwd = Some(path.as_ref().to_os_string()); + self + } + + pub fn get_cwd(&self) -> Option<&Path> { + self.cwd.as_ref().map(Path::new) + } + + pub fn construct(&self) -> Command { + let mut command = Command::new(&executable_path()); + + if let Some(cwd) = self.get_cwd() { + command.current_dir(cwd); + } + + command.env_clear(); + + let paths = vec![test_bins_path()]; + + let paths_joined = match std::env::join_paths(&paths) { + Ok(all) => all, + Err(_) => panic!("Couldn't join paths for PATH var."), + }; + + command.env(crate::NATIVE_PATH_ENV_VAR, paths_joined); + + for env_var in &self.environment_vars { + command.env(&env_var.name, &env_var.value); + } + + for arg in &self.arguments { + command.arg(arg); + } + + command + } +} diff --git a/crates/nu-test-support/src/playground/play.rs b/crates/nu-test-support/src/playground/play.rs index d9184bf679..2129352913 100644 --- a/crates/nu-test-support/src/playground/play.rs +++ b/crates/nu-test-support/src/playground/play.rs @@ -78,12 +78,8 @@ impl<'a> Playground<'a> { std::fs::create_dir(PathBuf::from(&nuplay_dir)).expect("can not create directory"); let fixtures = fs::fixtures(); -<<<<<<< HEAD - let fixtures = nu_path::canonicalize(fixtures.clone()).unwrap_or_else(|e| { -======= let cwd = std::env::current_dir().expect("Could not get current working directory."); let fixtures = nu_path::canonicalize_with(fixtures.clone(), cwd).unwrap_or_else(|e| { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce panic!( "Couldn't canonicalize fixtures path {}: {:?}", fixtures.display(), @@ -102,17 +98,6 @@ impl<'a> Playground<'a> { let playground_root = playground.root.path(); -<<<<<<< HEAD - let test = nu_path::canonicalize(playground_root.join(topic)).unwrap_or_else(|e| { - panic!( - "Couldn't canonicalize test path {}: {:?}", - playground_root.join(topic).display(), - e - ) - }); - - let root = nu_path::canonicalize(playground_root).unwrap_or_else(|e| { -======= let cwd = std::env::current_dir().expect("Could not get current working directory."); let test = nu_path::canonicalize_with(playground_root.join(topic), cwd).unwrap_or_else(|e| { @@ -125,7 +110,6 @@ impl<'a> Playground<'a> { let cwd = std::env::current_dir().expect("Could not get current working directory."); let root = nu_path::canonicalize_with(playground_root, cwd).unwrap_or_else(|e| { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce panic!( "Couldn't canonicalize tests root path {}: {:?}", playground_root.display(), diff --git a/crates/nu-test-support/src/playground/tests.rs b/crates/nu-test-support/src/playground/tests.rs index 9acfa44344..cc4daa597b 100644 --- a/crates/nu-test-support/src/playground/tests.rs +++ b/crates/nu-test-support/src/playground/tests.rs @@ -1,39 +1,13 @@ use crate::playground::Playground; use std::path::{Path, PathBuf}; -<<<<<<< HEAD -use super::matchers::says; -use hamcrest2::assert_that; -use hamcrest2::prelude::*; - -fn path(p: &Path) -> PathBuf { - nu_path::canonicalize(p) -======= fn path(p: &Path) -> PathBuf { let cwd = std::env::current_dir().expect("Could not get current working directory."); nu_path::canonicalize_with(p, cwd) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce .unwrap_or_else(|e| panic!("Couldn't canonicalize path {}: {:?}", p.display(), e)) } #[test] -<<<<<<< HEAD -fn asserts_standard_out_expectation_from_nu_executable() { - Playground::setup("topic", |_, nu| { - assert_that!(nu.cococo("andres"), says().stdout("andres")); - }) -} - -#[test] -fn asserts_standard_out_expectation_from_nu_executable_pipeline_fed() { - Playground::setup("topic", |_, nu| { - assert_that!(nu.pipeline("echo 'andres'"), says().stdout("andres")); - }) -} - -#[test] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn current_working_directory_in_sandbox_directory_created() { Playground::setup("topic", |dirs, nu| { let original_cwd = dirs.test(); diff --git a/crates/nu_plugin_chart/Cargo.toml b/crates/nu_plugin_chart/Cargo.toml new file mode 100644 index 0000000000..64f931558f --- /dev/null +++ b/crates/nu_plugin_chart/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "A plugin to display charts" +edition = "2018" +license = "MIT" +name = "nu_plugin_chart" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +nu-data = { path="../nu-data", version = "0.59.0" } +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-source = { path="../nu-source", version = "0.59.0" } +nu-value-ext = { path="../nu-value-ext", version = "0.59.0" } + +crossterm = "0.19.0" +tui = { version="0.15.0", default-features=false, features=["crossterm"] } diff --git a/crates/nu_plugin_chart/src/bar.rs b/crates/nu_plugin_chart/src/bar.rs new file mode 100644 index 0000000000..4a77d0eca5 --- /dev/null +++ b/crates/nu_plugin_chart/src/bar.rs @@ -0,0 +1,119 @@ +use nu_data::utils::Model; +use nu_errors::ShellError; + +use tui::{ + layout::{Constraint, Direction, Layout}, + style::{Color, Modifier, Style}, + widgets::BarChart, +}; + +const DEFAULT_COLOR: Color = Color::Green; + +pub struct Bar<'a> { + pub title: &'a str, + pub data: Vec<(&'a str, u64)>, + pub enhanced_graphics: bool, +} + +impl<'a> Bar<'a> { + pub fn from_model(model: &'a Model) -> Result, ShellError> { + let mut data = Vec::new(); + let mut data_points = Vec::new(); + + for percentages in model + .percentages + .table_entries() + .cloned() + .collect::>() + { + let mut percentages_collected = vec![]; + + for percentage in percentages.table_entries().cloned().collect::>() { + percentages_collected.push(percentage.as_u64()?); + } + + data_points.push(percentages_collected); + } + + let mark_in = if model.labels.y.len() <= 1 { + 0 + } else { + (model.labels.y.len() as f64 / 2.0).floor() as usize + }; + + for idx in 0..model.labels.x.len() { + let mut current = 0; + + loop { + let label = if current == mark_in { + model + .labels + .at(idx) + .ok_or_else(|| ShellError::untagged_runtime_error("Could not load data"))? + } else { + "" + }; + + let percentages_collected = data_points + .get(current) + .ok_or_else(|| ShellError::untagged_runtime_error("Could not load data"))?; + + data.push(( + label, + *percentages_collected + .get(idx) + .ok_or_else(|| ShellError::untagged_runtime_error("Could not load data"))?, + )); + + current += 1; + + if current == model.labels.y.len() { + break; + } + } + } + + Ok(Bar { + title: "Bar Chart", + data: (&data[..]).to_vec(), + enhanced_graphics: true, + }) + } + + pub fn draw(&mut self, ui: &mut tui::Terminal) -> std::io::Result<()> + where + T: tui::backend::Backend, + { + ui.draw(|f| { + let chunks = Layout::default() + .direction(Direction::Vertical) + .margin(0) + .constraints([Constraint::Percentage(100)].as_ref()) + .split(f.size()); + + let barchart = BarChart::default() + .data(&self.data) + .bar_width(9) + .bar_style(Style::default().fg(DEFAULT_COLOR)) + .value_style( + Style::default() + .bg(Color::Black) + .add_modifier(Modifier::BOLD), + ); + + f.render_widget(barchart, chunks[0]); + })?; + Ok(()) + } + + pub fn on_right(&mut self) { + let one_bar = self.data.remove(0); + self.data.push(one_bar); + } + + pub fn on_left(&mut self) { + if let Some(one_bar) = self.data.pop() { + self.data.insert(0, one_bar); + } + } +} diff --git a/crates/nu_plugin_chart/src/bin/nu_plugin_chart_bar.rs b/crates/nu_plugin_chart/src/bin/nu_plugin_chart_bar.rs new file mode 100644 index 0000000000..20ada96668 --- /dev/null +++ b/crates/nu_plugin_chart/src/bin/nu_plugin_chart_bar.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_chart::ChartBar; + +fn main() { + serve_plugin(&mut ChartBar::new()); +} diff --git a/crates/nu_plugin_chart/src/bin/nu_plugin_chart_line.rs b/crates/nu_plugin_chart/src/bin/nu_plugin_chart_line.rs new file mode 100644 index 0000000000..82ae4a00db --- /dev/null +++ b/crates/nu_plugin_chart/src/bin/nu_plugin_chart_line.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_chart::ChartLine; + +fn main() { + serve_plugin(&mut ChartLine::new()); +} diff --git a/crates/nu_plugin_chart/src/lib.rs b/crates/nu_plugin_chart/src/lib.rs new file mode 100644 index 0000000000..747c5bdcd4 --- /dev/null +++ b/crates/nu_plugin_chart/src/lib.rs @@ -0,0 +1,5 @@ +mod bar; +mod line; +mod nu; + +pub use nu::{ChartBar, ChartLine}; diff --git a/crates/nu_plugin_chart/src/line.rs b/crates/nu_plugin_chart/src/line.rs new file mode 100644 index 0000000000..53088a70d4 --- /dev/null +++ b/crates/nu_plugin_chart/src/line.rs @@ -0,0 +1,144 @@ +use nu_data::utils::Model; +use nu_errors::ShellError; + +use tui::{ + layout::{Constraint, Direction, Layout}, + style::{Color, Modifier, Style}, + symbols, + text::Span, + widgets::{Axis, Chart, Dataset, GraphType}, +}; + +const DEFAULT_COLOR: Color = Color::Green; + +const DEFAULT_LINE_COLORS: [Color; 5] = [ + Color::Green, + Color::Cyan, + Color::Magenta, + Color::Yellow, + Color::Red, +]; + +#[derive(Debug)] +pub struct Line { + x_labels: Vec, + x_range: [f64; 2], + y_range: [f64; 2], + datasets_names: Vec, + data: Vec>, +} + +impl<'a> Line { + pub fn from_model(model: &'a Model) -> Result { + Ok(Line { + x_labels: model.labels.x.to_vec(), + x_range: [ + model.ranges.0.start.as_u64()? as f64, + model.labels.x.len() as f64, + ], + y_range: [ + model.ranges.1.start.as_u64()? as f64, + model.ranges.1.end.as_u64()? as f64, + ], + datasets_names: if model.labels.y.len() == 1 { + vec!["".to_string()] + } else { + model.labels.y.to_vec() + }, + data: model + .data + .table_entries() + .collect::>() + .iter() + .map(|subset| { + subset + .table_entries() + .enumerate() + .map(|(idx, data_point)| { + ( + idx as f64, + if let Ok(point) = data_point.as_u64() { + point as f64 + } else { + 0.0 + }, + ) + }) + .collect::>() + }) + .collect::>(), + }) + } + + pub fn draw(&mut self, ui: &mut tui::Terminal) -> std::io::Result<()> + where + T: tui::backend::Backend, + { + ui.draw(|f| { + let chunks = Layout::default() + .direction(Direction::Vertical) + .margin(1) + .constraints([Constraint::Percentage(100)].as_ref()) + .split(f.size()); + + let x_labels = self + .x_labels + .iter() + .map(move |label| { + Span::styled(label, Style::default().add_modifier(Modifier::BOLD)) + }) + .collect::>(); + + let y_labels = vec![ + Span::styled( + self.y_range[0].to_string(), + Style::default().add_modifier(Modifier::BOLD), + ), + Span::raw(((self.y_range[0] + self.y_range[1]) / 2.0).to_string()), + Span::styled( + self.y_range[1].to_string(), + Style::default().add_modifier(Modifier::BOLD), + ), + ]; + + let marker = if x_labels.len() > 60 { + symbols::Marker::Braille + } else { + symbols::Marker::Dot + }; + + let datasets = self + .data + .iter() + .enumerate() + .map(|(idx, data_series)| { + Dataset::default() + .name(&self.datasets_names[idx]) + .marker(marker) + .graph_type(GraphType::Line) + .style( + Style::default() + .fg(*DEFAULT_LINE_COLORS.get(idx).unwrap_or(&DEFAULT_COLOR)), + ) + .data(data_series) + }) + .collect(); + + let chart = Chart::new(datasets) + .x_axis( + Axis::default() + .style(Style::default().fg(Color::Gray)) + .labels(x_labels) + .bounds(self.x_range), + ) + .y_axis( + Axis::default() + .style(Style::default().fg(Color::Gray)) + .labels(y_labels) + .bounds(self.y_range), + ); + f.render_widget(chart, chunks[0]); + })?; + Ok(()) + } +} diff --git a/crates/nu_plugin_chart/src/nu.rs b/crates/nu_plugin_chart/src/nu.rs new file mode 100644 index 0000000000..7b472a1675 --- /dev/null +++ b/crates/nu_plugin_chart/src/nu.rs @@ -0,0 +1,5 @@ +mod bar; +mod line; + +pub use bar::SubCommand as ChartBar; +pub use line::SubCommand as ChartLine; diff --git a/crates/nu_plugin_chart/src/nu/bar.rs b/crates/nu_plugin_chart/src/nu/bar.rs new file mode 100644 index 0000000000..4a47fc0e66 --- /dev/null +++ b/crates/nu_plugin_chart/src/nu/bar.rs @@ -0,0 +1,371 @@ +use nu_data::utils::{report as build_report, Model}; +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{CallInfo, ColumnPath, Primitive, Signature, SyntaxShape, UntaggedValue, Value}; +use nu_source::{Tagged, TaggedItem}; +use nu_value_ext::ValueExt; + +use crate::bar::Bar; + +use std::{ + error::Error, + io::stdout, + sync::mpsc, + thread, + time::{Duration, Instant}, +}; + +use crossterm::{ + event::{self, DisableMouseCapture, EnableMouseCapture, Event as CEvent, KeyCode}, + execute, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, +}; + +use tui::{backend::CrosstermBackend, Terminal}; + +enum Event { + Input(I), + Tick, +} + +pub enum Columns { + One(Tagged), + Two(Tagged, Tagged), + None, +} + +#[allow(clippy::type_complexity)] +pub struct SubCommand { + pub reduction: nu_data::utils::Reduction, + pub columns: Columns, + pub eval: Option Result + Send>>, + pub format: Option, +} + +impl Default for SubCommand { + fn default() -> Self { + Self::new() + } +} + +impl SubCommand { + pub fn new() -> SubCommand { + SubCommand { + reduction: nu_data::utils::Reduction::Count, + columns: Columns::None, + eval: None, + format: None, + } + } +} + +fn display(model: &Model) -> Result<(), Box> { + let mut app = Bar::from_model(model)?; + + enable_raw_mode()?; + + let mut stdout = stdout(); + execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; + + let backend = CrosstermBackend::new(stdout); + + let mut terminal = Terminal::new(backend)?; + + let (tx, rx) = mpsc::channel(); + + let tick_rate = Duration::from_millis(250); + thread::spawn(move || { + let mut last_tick = Instant::now(); + loop { + if event::poll(tick_rate - last_tick.elapsed()).is_ok() { + if let Ok(CEvent::Key(key)) = event::read() { + let _ = tx.send(Event::Input(key)); + } + } + if last_tick.elapsed() >= tick_rate { + let _ = tx.send(Event::Tick); + last_tick = Instant::now(); + } + } + }); + + terminal.clear()?; + + loop { + app.draw(&mut terminal)?; + + match rx.recv()? { + Event::Input(event) => match event.code { + KeyCode::Left => app.on_left(), + KeyCode::Right => app.on_right(), + KeyCode::Char('q') => { + disable_raw_mode()?; + execute!( + terminal.backend_mut(), + LeaveAlternateScreen, + DisableMouseCapture + )?; + terminal.show_cursor()?; + break; + } + _ => { + disable_raw_mode()?; + execute!( + terminal.backend_mut(), + LeaveAlternateScreen, + DisableMouseCapture + )?; + terminal.show_cursor()?; + break; + } + }, + Event::Tick => {} + } + } + + Ok(()) +} + +impl Plugin for SubCommand { + fn config(&mut self) -> Result { + Ok(Signature::build("chart bar") + .desc("Bar charts") + .switch("acc", "accumulate values", Some('a')) + .optional( + "columns", + SyntaxShape::Any, + "the columns to chart [x-axis y-axis]", + ) + .named( + "use", + SyntaxShape::ColumnPath, + "column to use for evaluation", + Some('u'), + ) + .named( + "format", + SyntaxShape::String, + "Specify date and time formatting", + Some('f'), + )) + } + + fn sink(&mut self, call_info: CallInfo, input: Vec) { + if let Some(Value { + value: UntaggedValue::Primitive(Primitive::Boolean(true)), + .. + }) = call_info.args.get("acc") + { + self.reduction = nu_data::utils::Reduction::Accumulate; + } + + let _ = self.run(call_info, input); + } +} + +impl SubCommand { + fn run(&mut self, call_info: CallInfo, input: Vec) -> Result<(), ShellError> { + let args = call_info.args; + let name = call_info.name_tag; + + self.eval = if let Some(path) = args.get("use") { + Some(evaluator(path.as_column_path()?.item)) + } else { + None + }; + + self.format = if let Some(fmt) = args.get("format") { + Some(fmt.as_string()?) + } else { + None + }; + + for arg in args.positional_iter() { + match arg { + Value { + value: UntaggedValue::Primitive(Primitive::String(column)), + tag, + } => { + let column = column.clone(); + self.columns = Columns::One(column.tagged(tag)); + } + Value { + value: UntaggedValue::Table(arguments), + tag, + } => { + if arguments.len() > 1 { + let col1 = arguments + .get(0) + .ok_or_else(|| { + ShellError::labeled_error( + "expected file and replace strings eg) [find replace]", + "missing find-replace values", + tag, + ) + })? + .as_string()? + .tagged(tag); + + let col2 = arguments + .get(1) + .ok_or_else(|| { + ShellError::labeled_error( + "expected file and replace strings eg) [find replace]", + "missing find-replace values", + tag, + ) + })? + .as_string()? + .tagged(tag); + + self.columns = Columns::Two(col1, col2); + } else { + let col1 = arguments + .get(0) + .ok_or_else(|| { + ShellError::labeled_error( + "expected file and replace strings eg) [find replace]", + "missing find-replace values", + tag, + ) + })? + .as_string()? + .tagged(tag); + + self.columns = Columns::One(col1); + } + } + _ => {} + } + } + + let data = UntaggedValue::table(&input).into_value(&name); + + match &self.columns { + Columns::Two(col1, col2) => { + let key = col1.clone(); + let fmt = self.format.clone(); + + let grouper = Box::new(move |_: usize, row: &Value| { + let key = key.clone(); + let fmt = fmt.clone(); + + match row.get_data_by_key(key.borrow_spanned()) { + Some(key) => { + if let Some(fmt) = fmt { + let callback = nu_data::utils::helpers::date_formatter(fmt); + callback(&key, "nothing".to_string()) + } else { + nu_value_ext::as_string(&key) + } + } + None => Err(ShellError::labeled_error( + "unknown column", + "unknown column", + key.tag(), + )), + } + }); + + let key = col2.clone(); + let splitter = Box::new(move |_: usize, row: &Value| { + let key = key.clone(); + + match row.get_data_by_key(key.borrow_spanned()) { + Some(key) => nu_value_ext::as_string(&key), + None => Err(ShellError::labeled_error( + "unknown column", + "unknown column", + key.tag(), + )), + } + }); + + let formatter = if self.format.is_some() { + let default = String::from("%b-%Y"); + + let string_fmt = self.format.as_ref().unwrap_or(&default); + + Some(nu_data::utils::helpers::date_formatter( + string_fmt.to_string(), + )) + } else { + None + }; + + let options = nu_data::utils::Operation { + grouper: Some(grouper), + splitter: Some(splitter), + format: &formatter, + eval: &self.eval, + reduction: &self.reduction, + }; + + let _ = display(&build_report(&data, options, &name)?); + } + Columns::One(col) => { + let key = col.clone(); + let fmt = self.format.clone(); + + let grouper = Box::new(move |_: usize, row: &Value| { + let key = key.clone(); + let fmt = fmt.clone(); + + match row.get_data_by_key(key.borrow_spanned()) { + Some(key) => { + if let Some(fmt) = fmt { + let callback = nu_data::utils::helpers::date_formatter(fmt); + callback(&key, "nothing".to_string()) + } else { + nu_value_ext::as_string(&key) + } + } + None => Err(ShellError::labeled_error( + "unknown column", + "unknown column", + key.tag(), + )), + } + }); + + let formatter = if self.format.is_some() { + let default = String::from("%b-%Y"); + + let string_fmt = self.format.as_ref().unwrap_or(&default); + + Some(nu_data::utils::helpers::date_formatter( + string_fmt.to_string(), + )) + } else { + None + }; + + let options = nu_data::utils::Operation { + grouper: Some(grouper), + splitter: None, + format: &formatter, + eval: &self.eval, + reduction: &self.reduction, + }; + + let _ = display(&build_report(&data, options, &name)?); + } + _ => {} + } + + Ok(()) + } +} + +pub fn evaluator(by: ColumnPath) -> Box Result + Send> { + Box::new(move |_: usize, value: &Value| { + let path = by.clone(); + + let eval = nu_value_ext::get_data_by_column_path(value, &path, move |_, _, error| error); + + match eval { + Ok(with_value) => Ok(with_value), + Err(reason) => Err(reason), + } + }) +} diff --git a/crates/nu_plugin_chart/src/nu/line.rs b/crates/nu_plugin_chart/src/nu/line.rs new file mode 100644 index 0000000000..91f27c5ce7 --- /dev/null +++ b/crates/nu_plugin_chart/src/nu/line.rs @@ -0,0 +1,369 @@ +use nu_data::utils::{report as build_report, Model}; +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{CallInfo, ColumnPath, Primitive, Signature, SyntaxShape, UntaggedValue, Value}; +use nu_source::{Tagged, TaggedItem}; +use nu_value_ext::ValueExt; + +use crate::line::Line; + +use std::{ + error::Error, + io::stdout, + sync::mpsc, + thread, + time::{Duration, Instant}, +}; + +use crossterm::{ + event::{self, DisableMouseCapture, EnableMouseCapture, Event as CEvent, KeyCode}, + execute, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, +}; + +use tui::{backend::CrosstermBackend, Terminal}; + +enum Event { + Input(I), + Tick, +} + +pub enum Columns { + One(Tagged), + Two(Tagged, Tagged), + None, +} + +#[allow(clippy::type_complexity)] +pub struct SubCommand { + pub reduction: nu_data::utils::Reduction, + pub columns: Columns, + pub eval: Option Result + Send>>, + pub format: Option, +} + +impl Default for SubCommand { + fn default() -> Self { + Self::new() + } +} + +impl SubCommand { + pub fn new() -> SubCommand { + SubCommand { + reduction: nu_data::utils::Reduction::Count, + columns: Columns::None, + eval: None, + format: None, + } + } +} + +fn display(model: &Model) -> Result<(), Box> { + let mut app = Line::from_model(model)?; + + enable_raw_mode()?; + + let mut stdout = stdout(); + execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; + + let backend = CrosstermBackend::new(stdout); + + let mut terminal = Terminal::new(backend)?; + + let (tx, rx) = mpsc::channel(); + + let tick_rate = Duration::from_millis(250); + thread::spawn(move || { + let mut last_tick = Instant::now(); + loop { + if event::poll(tick_rate - last_tick.elapsed()).is_ok() { + if let Ok(CEvent::Key(key)) = event::read() { + let _ = tx.send(Event::Input(key)); + } + } + if last_tick.elapsed() >= tick_rate { + let _ = tx.send(Event::Tick); + last_tick = Instant::now(); + } + } + }); + + terminal.clear()?; + + loop { + app.draw(&mut terminal)?; + + match rx.recv()? { + Event::Input(event) => match event.code { + KeyCode::Char('q') => { + disable_raw_mode()?; + execute!( + terminal.backend_mut(), + LeaveAlternateScreen, + DisableMouseCapture + )?; + terminal.show_cursor()?; + break; + } + _ => { + disable_raw_mode()?; + execute!( + terminal.backend_mut(), + LeaveAlternateScreen, + DisableMouseCapture + )?; + terminal.show_cursor()?; + break; + } + }, + Event::Tick => {} + } + } + + Ok(()) +} + +impl Plugin for SubCommand { + fn config(&mut self) -> Result { + Ok(Signature::build("chart line") + .desc("Line charts") + .switch("acc", "accumulate values", Some('a')) + .optional( + "columns", + SyntaxShape::Any, + "the columns to chart [x-axis y-axis]", + ) + .named( + "use", + SyntaxShape::ColumnPath, + "column to use for evaluation", + Some('u'), + ) + .named( + "format", + SyntaxShape::String, + "Specify date and time formatting", + Some('f'), + )) + } + + fn sink(&mut self, call_info: CallInfo, input: Vec) { + if let Some(Value { + value: UntaggedValue::Primitive(Primitive::Boolean(true)), + .. + }) = call_info.args.get("acc") + { + self.reduction = nu_data::utils::Reduction::Accumulate; + } + + let _ = self.run(call_info, input); + } +} + +impl SubCommand { + fn run(&mut self, call_info: CallInfo, input: Vec) -> Result<(), ShellError> { + let args = call_info.args; + let name = call_info.name_tag; + + self.eval = if let Some(path) = args.get("use") { + Some(evaluator(path.as_column_path()?.item)) + } else { + None + }; + + self.format = if let Some(fmt) = args.get("format") { + Some(fmt.as_string()?) + } else { + None + }; + + for arg in args.positional_iter() { + match arg { + Value { + value: UntaggedValue::Primitive(Primitive::String(column)), + tag, + } => { + let column = column.clone(); + self.columns = Columns::One(column.tagged(tag)); + } + Value { + value: UntaggedValue::Table(arguments), + tag, + } => { + if arguments.len() > 1 { + let col1 = arguments + .get(0) + .ok_or_else(|| { + ShellError::labeled_error( + "expected file and replace strings eg) [find replace]", + "missing find-replace values", + tag, + ) + })? + .as_string()? + .tagged(tag); + + let col2 = arguments + .get(1) + .ok_or_else(|| { + ShellError::labeled_error( + "expected file and replace strings eg) [find replace]", + "missing find-replace values", + tag, + ) + })? + .as_string()? + .tagged(tag); + + self.columns = Columns::Two(col1, col2); + } else { + let col1 = arguments + .get(0) + .ok_or_else(|| { + ShellError::labeled_error( + "expected file and replace strings eg) [find replace]", + "missing find-replace values", + tag, + ) + })? + .as_string()? + .tagged(tag); + + self.columns = Columns::One(col1); + } + } + _ => {} + } + } + + let data = UntaggedValue::table(&input).into_value(&name); + + match &self.columns { + Columns::Two(col1, col2) => { + let key = col1.clone(); + let fmt = self.format.clone(); + + let grouper = Box::new(move |_: usize, row: &Value| { + let key = key.clone(); + let fmt = fmt.clone(); + + match row.get_data_by_key(key.borrow_spanned()) { + Some(key) => { + if let Some(fmt) = fmt { + let callback = nu_data::utils::helpers::date_formatter(fmt); + callback(&key, "nothing".to_string()) + } else { + nu_value_ext::as_string(&key) + } + } + None => Err(ShellError::labeled_error( + "unknown column", + "unknown column", + key.tag(), + )), + } + }); + + let key = col2.clone(); + let splitter = Box::new(move |_: usize, row: &Value| { + let key = key.clone(); + + match row.get_data_by_key(key.borrow_spanned()) { + Some(key) => nu_value_ext::as_string(&key), + None => Err(ShellError::labeled_error( + "unknown column", + "unknown column", + key.tag(), + )), + } + }); + + let formatter = if self.format.is_some() { + let default = String::from("%b-%Y"); + + let string_fmt = self.format.as_ref().unwrap_or(&default); + + Some(nu_data::utils::helpers::date_formatter( + string_fmt.to_string(), + )) + } else { + None + }; + + let options = nu_data::utils::Operation { + grouper: Some(grouper), + splitter: Some(splitter), + format: &formatter, + eval: &self.eval, + reduction: &self.reduction, + }; + + let _ = display(&build_report(&data, options, &name)?); + } + Columns::One(col) => { + let key = col.clone(); + let fmt = self.format.clone(); + + let grouper = Box::new(move |_: usize, row: &Value| { + let key = key.clone(); + let fmt = fmt.clone(); + + match row.get_data_by_key(key.borrow_spanned()) { + Some(key) => { + if let Some(fmt) = fmt { + let callback = nu_data::utils::helpers::date_formatter(fmt); + callback(&key, "nothing".to_string()) + } else { + nu_value_ext::as_string(&key) + } + } + None => Err(ShellError::labeled_error( + "unknown column", + "unknown column", + key.tag(), + )), + } + }); + + let formatter = if self.format.is_some() { + let default = String::from("%b-%Y"); + + let string_fmt = self.format.as_ref().unwrap_or(&default); + + Some(nu_data::utils::helpers::date_formatter( + string_fmt.to_string(), + )) + } else { + None + }; + + let options = nu_data::utils::Operation { + grouper: Some(grouper), + splitter: None, + format: &formatter, + eval: &self.eval, + reduction: &self.reduction, + }; + + let _ = display(&build_report(&data, options, &name)?); + } + _ => {} + } + + Ok(()) + } +} + +pub fn evaluator(by: ColumnPath) -> Box Result + Send> { + Box::new(move |_: usize, value: &Value| { + let path = by.clone(); + + let eval = nu_value_ext::get_data_by_column_path(value, &path, move |_, _, error| error); + + match eval { + Ok(with_value) => Ok(with_value), + Err(reason) => Err(reason), + } + }) +} diff --git a/crates/nu_plugin_example/Cargo.toml b/crates/nu_plugin_example/Cargo.toml index 89cea551c8..4f75fa3311 100644 --- a/crates/nu_plugin_example/Cargo.toml +++ b/crates/nu_plugin_example/Cargo.toml @@ -4,8 +4,8 @@ description = "A version incrementer plugin for Nushell" edition = "2021" license = "MIT" name = "nu_plugin_example" -version = "0.1.0" +version = "0.59.0" [dependencies] -nu-plugin = { path="../nu-plugin", version = "0.1.0" } -nu-protocol = { path="../nu-protocol", version = "0.1.0", features = ["plugin"]} +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0", features = ["plugin"]} diff --git a/crates/nu_plugin_from_bson/Cargo.toml b/crates/nu_plugin_from_bson/Cargo.toml new file mode 100644 index 0000000000..6e6d4c3234 --- /dev/null +++ b/crates/nu_plugin_from_bson/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "A converter plugin to the bson format for Nushell" +edition = "2018" +license = "MIT" +name = "nu_plugin_from_bson" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +bigdecimal = { package = "bigdecimal", version = "0.3.0", features = ["serde"] } +bson = { version = "2.0.1", features = [ "chrono-0_4" ] } +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-source = { path="../nu-source", version = "0.59.0" } + +[build-dependencies] diff --git a/crates/nu_plugin_from_bson/src/from_bson.rs b/crates/nu_plugin_from_bson/src/from_bson.rs new file mode 100644 index 0000000000..115c52492e --- /dev/null +++ b/crates/nu_plugin_from_bson/src/from_bson.rs @@ -0,0 +1,212 @@ +use bigdecimal::BigDecimal; +use bson::{spec::BinarySubtype, Bson}; +use nu_errors::{ExpectedRange, ShellError}; +use nu_protocol::{Primitive, ReturnSuccess, ReturnValue, TaggedDictBuilder, UntaggedValue, Value}; +use nu_source::{SpannedItem, Tag}; +use std::str::FromStr; + +#[derive(Default)] +pub struct FromBson { + pub state: Vec, + pub name_tag: Tag, +} + +impl FromBson { + pub fn new() -> FromBson { + FromBson { + state: vec![], + name_tag: Tag::unknown(), + } + } +} + +fn bson_array(input: &[Bson], tag: Tag) -> Result, ShellError> { + let mut out = vec![]; + + for value in input { + out.push(convert_bson_value_to_nu_value(value, &tag)?); + } + + Ok(out) +} + +fn convert_bson_value_to_nu_value(v: &Bson, tag: impl Into) -> Result { + let tag = tag.into(); + let span = tag.span; + + Ok(match v { + Bson::Double(n) => UntaggedValue::Primitive(Primitive::from(*n)).into_value(&tag), + Bson::String(s) => { + UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(&tag) + } + Bson::Array(a) => UntaggedValue::Table(bson_array(a, tag.clone())?).into_value(&tag), + Bson::Document(doc) => { + let mut collected = TaggedDictBuilder::new(tag.clone()); + for (k, v) in doc { + collected.insert_value(k.clone(), convert_bson_value_to_nu_value(v, &tag)?); + } + + collected.into_value() + } + Bson::Boolean(b) => UntaggedValue::Primitive(Primitive::Boolean(*b)).into_value(&tag), + Bson::Null => UntaggedValue::Primitive(Primitive::Nothing).into_value(&tag), + Bson::RegularExpression(regx) => { + let mut collected = TaggedDictBuilder::new(tag.clone()); + collected.insert_value( + "$regex".to_string(), + UntaggedValue::Primitive(Primitive::String(String::from(®x.pattern))) + .into_value(&tag), + ); + collected.insert_value( + "$options".to_string(), + UntaggedValue::Primitive(Primitive::String(String::from(®x.options))) + .into_value(&tag), + ); + collected.into_value() + } + Bson::Int32(n) => UntaggedValue::int(*n).into_value(&tag), + Bson::Int64(n) => UntaggedValue::int(*n).into_value(&tag), + Bson::Decimal128(n) => { + // TODO: this really isn't great, and we should update this to do a higher + // fidelity translation + let decimal = BigDecimal::from_str(&n.to_string()).map_err(|_| { + ShellError::range_error( + ExpectedRange::BigDecimal, + &n.spanned(span), + "converting BSON Decimal128 to BigDecimal".to_owned(), + ) + })?; + UntaggedValue::Primitive(Primitive::Decimal(decimal)).into_value(&tag) + } + Bson::JavaScriptCode(js) => { + let mut collected = TaggedDictBuilder::new(tag.clone()); + collected.insert_value( + "$javascript".to_string(), + UntaggedValue::Primitive(Primitive::String(String::from(js))).into_value(&tag), + ); + collected.into_value() + } + Bson::JavaScriptCodeWithScope(js) => { + let mut collected = TaggedDictBuilder::new(tag.clone()); + collected.insert_value( + "$javascript".to_string(), + UntaggedValue::Primitive(Primitive::String(String::from(&js.code))) + .into_value(&tag), + ); + collected.insert_value( + "$scope".to_string(), + convert_bson_value_to_nu_value(&Bson::Document(js.scope.to_owned()), tag)?, + ); + collected.into_value() + } + Bson::Timestamp(ts) => { + let mut collected = TaggedDictBuilder::new(tag.clone()); + collected.insert_value( + "$timestamp".to_string(), + UntaggedValue::int(ts.time).into_value(&tag), + ); + collected.into_value() + } + Bson::Binary(binary) => { + let mut collected = TaggedDictBuilder::new(tag.clone()); + collected.insert_value( + "$binary_subtype".to_string(), + match binary.subtype { + BinarySubtype::UserDefined(u) => UntaggedValue::int(u), + _ => UntaggedValue::Primitive(Primitive::String(binary_subtype_to_string( + binary.subtype, + ))), + } + .into_value(&tag), + ); + collected.insert_value( + "$binary".to_string(), + UntaggedValue::Primitive(Primitive::Binary(binary.bytes.to_owned())) + .into_value(&tag), + ); + collected.into_value() + } + Bson::ObjectId(obj_id) => { + let mut collected = TaggedDictBuilder::new(tag.clone()); + collected.insert_value( + "$object_id".to_string(), + UntaggedValue::Primitive(Primitive::String(obj_id.to_hex())).into_value(&tag), + ); + collected.into_value() + } + Bson::DateTime(dt) => { + UntaggedValue::Primitive(Primitive::Date(dt.to_chrono().into())).into_value(&tag) + } + Bson::Symbol(s) => { + let mut collected = TaggedDictBuilder::new(tag.clone()); + collected.insert_value( + "$symbol".to_string(), + UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(&tag), + ); + collected.into_value() + } + Bson::Undefined | Bson::MaxKey | Bson::MinKey | Bson::DbPointer(_) => { + // TODO Impelmenting Bson::Undefined, Bson::MaxKey, Bson::MinKey and Bson::DbPointer + // These Variants weren't present in the previous version. + TaggedDictBuilder::new(tag).into_value() + } + }) +} + +fn binary_subtype_to_string(bst: BinarySubtype) -> String { + match bst { + BinarySubtype::Generic => "generic", + BinarySubtype::Function => "function", + BinarySubtype::BinaryOld => "binary_old", + BinarySubtype::UuidOld => "uuid_old", + BinarySubtype::Uuid => "uuid", + BinarySubtype::Md5 => "md5", + _ => unreachable!(), + } + .to_string() +} + +#[derive(Debug)] +struct BytesReader { + pos: usize, + inner: Vec, +} + +impl BytesReader { + fn new(bytes: Vec) -> BytesReader { + BytesReader { + pos: 0, + inner: bytes, + } + } +} + +impl std::io::Read for BytesReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let src: &mut &[u8] = &mut self.inner[self.pos..].as_ref(); + let diff = src.read(buf)?; + self.pos += diff; + Ok(diff) + } +} + +pub fn from_bson_bytes_to_value(bytes: Vec, tag: impl Into) -> Result { + let mut docs = Vec::new(); + let mut b_reader = BytesReader::new(bytes); + while let Ok(v) = bson::de::from_reader(&mut b_reader) { + docs.push(Bson::Document(v)); + } + + convert_bson_value_to_nu_value(&Bson::Array(docs), tag) +} + +pub fn from_bson(bytes: Vec, name_tag: Tag) -> Result, ShellError> { + match from_bson_bytes_to_value(bytes, name_tag.clone()) { + Ok(x) => Ok(vec![ReturnSuccess::value(x)]), + Err(_) => Err(ShellError::labeled_error( + "Could not parse as BSON", + "input cannot be parsed as BSON", + name_tag, + )), + } +} diff --git a/crates/nu_plugin_from_bson/src/lib.rs b/crates/nu_plugin_from_bson/src/lib.rs new file mode 100644 index 0000000000..c037ee0289 --- /dev/null +++ b/crates/nu_plugin_from_bson/src/lib.rs @@ -0,0 +1,4 @@ +mod from_bson; +mod nu; + +pub use from_bson::FromBson; diff --git a/crates/nu_plugin_from_bson/src/main.rs b/crates/nu_plugin_from_bson/src/main.rs new file mode 100644 index 0000000000..bec813d017 --- /dev/null +++ b/crates/nu_plugin_from_bson/src/main.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_from_bson::FromBson; + +fn main() { + serve_plugin(&mut FromBson::new()) +} diff --git a/crates/nu_plugin_from_bson/src/nu/mod.rs b/crates/nu_plugin_from_bson/src/nu/mod.rs new file mode 100644 index 0000000000..0a6584d01f --- /dev/null +++ b/crates/nu_plugin_from_bson/src/nu/mod.rs @@ -0,0 +1,46 @@ +#[cfg(test)] +mod tests; + +use crate::FromBson; +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{CallInfo, Primitive, ReturnValue, Signature, UntaggedValue, Value}; +use nu_source::Tag; + +impl Plugin for FromBson { + fn config(&mut self) -> Result { + Ok(Signature::build("from bson") + .desc("Convert from .bson binary into table") + .filter()) + } + + fn begin_filter(&mut self, call_info: CallInfo) -> Result, ShellError> { + self.name_tag = call_info.name_tag; + Ok(vec![]) + } + + fn filter(&mut self, input: Value) -> Result, ShellError> { + match input { + Value { + value: UntaggedValue::Primitive(Primitive::Binary(b)), + .. + } => { + self.state.extend_from_slice(&b); + } + Value { tag, .. } => { + return Err(ShellError::labeled_error_with_secondary( + "Expected binary from pipeline", + "requires binary input", + self.name_tag.clone(), + "value originates from here", + tag, + )); + } + } + Ok(vec![]) + } + + fn end_filter(&mut self) -> Result, ShellError> { + crate::from_bson::from_bson(self.state.clone(), Tag::unknown()) + } +} diff --git a/crates/nu_plugin_from_bson/src/nu/tests.rs b/crates/nu_plugin_from_bson/src/nu/tests.rs new file mode 100644 index 0000000000..d14c19bee3 --- /dev/null +++ b/crates/nu_plugin_from_bson/src/nu/tests.rs @@ -0,0 +1 @@ +mod integration {} diff --git a/crates/nu_plugin_from_mp4/Cargo.toml b/crates/nu_plugin_from_mp4/Cargo.toml new file mode 100644 index 0000000000..f34bd04923 --- /dev/null +++ b/crates/nu_plugin_from_mp4/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "A converter plugin to the mp4 format for Nushell" +edition = "2018" +license = "MIT" +name = "nu_plugin_from_mp4" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-source = { path="../nu-source", version = "0.59.0" } +tempfile = "3.2.0" +mp4 = "0.9.0" + +[build-dependencies] diff --git a/crates/nu_plugin_from_mp4/src/from_mp4.rs b/crates/nu_plugin_from_mp4/src/from_mp4.rs new file mode 100644 index 0000000000..671cc29339 --- /dev/null +++ b/crates/nu_plugin_from_mp4/src/from_mp4.rs @@ -0,0 +1,174 @@ +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, ReturnValue, TaggedDictBuilder, UntaggedValue, Value}; +use nu_source::Tag; +use std::fs::File; +use std::io::Write; +use std::path::Path; + +#[derive(Default)] +pub struct FromMp4 { + pub state: Vec, + pub name_tag: Tag, +} + +impl FromMp4 { + pub fn new() -> Self { + Self { + state: vec![], + name_tag: Tag::unknown(), + } + } +} + +pub fn convert_mp4_file_to_nu_value(path: &Path, tag: Tag) -> Result { + let mp4 = mp4::read_mp4(File::open(path).expect("Could not open mp4 file to read metadata"))?; + + let mut dict = TaggedDictBuilder::new(tag.clone()); + + // Build tracks table + let mut tracks = Vec::new(); + for track in mp4.tracks().values() { + let mut curr_track_dict = TaggedDictBuilder::new(tag.clone()); + + curr_track_dict.insert_untagged("track id", UntaggedValue::int(track.track_id())); + + curr_track_dict.insert_untagged( + "track type", + match track.track_type() { + Ok(t) => UntaggedValue::string(t.to_string()), + Err(_) => UntaggedValue::from("Unknown"), + }, + ); + + curr_track_dict.insert_untagged( + "media type", + match track.media_type() { + Ok(t) => UntaggedValue::string(t.to_string()), + Err(_) => UntaggedValue::from("Unknown"), + }, + ); + + curr_track_dict.insert_untagged( + "box type", + match track.box_type() { + Ok(t) => UntaggedValue::string(t.to_string()), + Err(_) => UntaggedValue::from("Unknown"), + }, + ); + + curr_track_dict.insert_untagged("width", UntaggedValue::int(track.width())); + curr_track_dict.insert_untagged("height", UntaggedValue::int(track.height())); + curr_track_dict.insert_untagged("frame_rate", UntaggedValue::from(track.frame_rate())); + + curr_track_dict.insert_untagged( + "sample freq index", + match track.sample_freq_index() { + Ok(sfi) => UntaggedValue::string(sfi.freq().to_string()), // this is a string for formatting reasons + Err(_) => UntaggedValue::from("Unknown"), + }, + ); + + curr_track_dict.insert_untagged( + "channel config", + match track.channel_config() { + Ok(cc) => UntaggedValue::string(cc.to_string()), + Err(_) => UntaggedValue::from("Unknown"), + }, + ); + + curr_track_dict.insert_untagged("language", UntaggedValue::string(track.language())); + curr_track_dict.insert_untagged("timescale", UntaggedValue::int(track.timescale())); + curr_track_dict.insert_untagged( + "duration", + UntaggedValue::duration(track.duration().as_nanos()), + ); + curr_track_dict.insert_untagged("bitrate", UntaggedValue::int(track.bitrate())); + curr_track_dict.insert_untagged("sample count", UntaggedValue::int(track.sample_count())); + + curr_track_dict.insert_untagged( + "video profile", + match track.video_profile() { + Ok(vp) => UntaggedValue::string(vp.to_string()), + Err(_) => UntaggedValue::from("Unknown"), + }, + ); + + curr_track_dict.insert_untagged( + "audio profile", + match track.audio_profile() { + Ok(ap) => UntaggedValue::string(ap.to_string()), + Err(_) => UntaggedValue::from("Unknown"), + }, + ); + + curr_track_dict.insert_untagged( + "sequence parameter set", + match track.sequence_parameter_set() { + Ok(sps) => UntaggedValue::string(format!("{:X?}", sps)), + Err(_) => UntaggedValue::from("Unknown"), + }, + ); + + curr_track_dict.insert_untagged( + "picture parameter set", + match track.picture_parameter_set() { + Ok(pps) => UntaggedValue::string(format!("{:X?}", pps)), + Err(_) => UntaggedValue::from("Unknown"), + }, + ); + + // push curr track to tracks vec + tracks.push(curr_track_dict.into_value()); + } + + dict.insert_untagged("size", UntaggedValue::big_int(mp4.size())); + + dict.insert_untagged( + "major brand", + UntaggedValue::string(mp4.major_brand().to_string()), + ); + + dict.insert_untagged("minor version", UntaggedValue::int(mp4.minor_version())); + + dict.insert_untagged( + "compatible brands", + UntaggedValue::string(format!("{:?}", mp4.compatible_brands())), + ); + + dict.insert_untagged( + "duration", + UntaggedValue::duration(mp4.duration().as_nanos()), + ); + + dict.insert_untagged("timescale", UntaggedValue::int(mp4.timescale())); + dict.insert_untagged("is fragmented", UntaggedValue::boolean(mp4.is_fragmented())); + dict.insert_untagged("tracks", UntaggedValue::Table(tracks).into_value(&tag)); + + Ok(dict.into_value()) +} + +pub fn from_mp4_bytes_to_value(mut bytes: Vec, tag: Tag) -> Result { + let mut tempfile = tempfile::NamedTempFile::new()?; + tempfile.write_all(bytes.as_mut_slice())?; + match convert_mp4_file_to_nu_value(tempfile.path(), tag) { + Ok(value) => Ok(value), + Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)), + } +} + +pub fn from_mp4(bytes: Vec, name_tag: Tag) -> Result, ShellError> { + match from_mp4_bytes_to_value(bytes, name_tag.clone()) { + Ok(x) => match x { + Value { + value: UntaggedValue::Table(list), + .. + } => Ok(list.into_iter().map(ReturnSuccess::value).collect()), + _ => Ok(vec![ReturnSuccess::value(x)]), + }, + Err(_) => Err(ShellError::labeled_error( + "Could not parse as MP4", + "input cannot be parsed as MP4", + &name_tag, + )), + } +} diff --git a/crates/nu_plugin_from_mp4/src/lib.rs b/crates/nu_plugin_from_mp4/src/lib.rs new file mode 100644 index 0000000000..8de6281f24 --- /dev/null +++ b/crates/nu_plugin_from_mp4/src/lib.rs @@ -0,0 +1,4 @@ +mod from_mp4; +mod nu; + +pub use from_mp4::FromMp4; diff --git a/crates/nu_plugin_from_mp4/src/main.rs b/crates/nu_plugin_from_mp4/src/main.rs new file mode 100644 index 0000000000..539b494cf6 --- /dev/null +++ b/crates/nu_plugin_from_mp4/src/main.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_from_mp4::FromMp4; + +fn main() { + serve_plugin(&mut FromMp4::new()) +} diff --git a/crates/nu_plugin_from_mp4/src/nu/mod.rs b/crates/nu_plugin_from_mp4/src/nu/mod.rs new file mode 100644 index 0000000000..4aa09ca7d5 --- /dev/null +++ b/crates/nu_plugin_from_mp4/src/nu/mod.rs @@ -0,0 +1,46 @@ +#[cfg(test)] +mod tests; + +use crate::FromMp4; +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{CallInfo, Primitive, ReturnValue, Signature, UntaggedValue, Value}; +use nu_source::Tag; + +impl Plugin for FromMp4 { + fn config(&mut self) -> Result { + Ok(Signature::build("from mp4") + .desc("Get meta-data of mp4 file") + .filter()) + } + + fn begin_filter(&mut self, call_info: CallInfo) -> Result, ShellError> { + self.name_tag = call_info.name_tag; + Ok(vec![]) + } + + fn filter(&mut self, input: Value) -> Result, ShellError> { + match input { + Value { + value: UntaggedValue::Primitive(Primitive::Binary(b)), + .. + } => { + self.state.extend_from_slice(&b); + } + Value { tag, .. } => { + return Err(ShellError::labeled_error_with_secondary( + "Expected binary from pipeline", + "requires binary input", + self.name_tag.clone(), + "value originates from here", + tag, + )); + } + } + Ok(vec![]) + } + + fn end_filter(&mut self) -> Result, ShellError> { + crate::from_mp4::from_mp4(self.state.clone(), Tag::unknown()) + } +} diff --git a/crates/nu_plugin_from_mp4/src/nu/tests.rs b/crates/nu_plugin_from_mp4/src/nu/tests.rs new file mode 100644 index 0000000000..d14c19bee3 --- /dev/null +++ b/crates/nu_plugin_from_mp4/src/nu/tests.rs @@ -0,0 +1 @@ +mod integration {} diff --git a/crates/nu_plugin_from_sqlite/Cargo.toml b/crates/nu_plugin_from_sqlite/Cargo.toml new file mode 100644 index 0000000000..7a9eb4c363 --- /dev/null +++ b/crates/nu_plugin_from_sqlite/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "A converter plugin to the bson format for Nushell" +edition = "2018" +license = "MIT" +name = "nu_plugin_from_sqlite" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +bigdecimal = { package = "bigdecimal", version = "0.3.0", features = ["serde"] } +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-source = { path="../nu-source", version = "0.59.0" } +tempfile = "3.2.0" + +[dependencies.rusqlite] +features = ["bundled", "blob"] +version = "0.26.1" + +[build-dependencies] diff --git a/crates/nu_plugin_from_sqlite/src/from_sqlite.rs b/crates/nu_plugin_from_sqlite/src/from_sqlite.rs new file mode 100644 index 0000000000..da7bb00da5 --- /dev/null +++ b/crates/nu_plugin_from_sqlite/src/from_sqlite.rs @@ -0,0 +1,138 @@ +use bigdecimal::FromPrimitive; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, ReturnValue, TaggedDictBuilder, UntaggedValue, Value}; +use nu_source::Tag; +use rusqlite::{types::ValueRef, Connection, Row}; +use std::io::Write; +use std::path::Path; + +#[derive(Default)] +pub struct FromSqlite { + pub state: Vec, + pub name_tag: Tag, + pub tables: Vec, +} + +impl FromSqlite { + pub fn new() -> FromSqlite { + FromSqlite { + state: vec![], + name_tag: Tag::unknown(), + tables: vec![], + } + } +} + +pub fn convert_sqlite_file_to_nu_value( + path: &Path, + tag: impl Into + Clone, + tables: Vec, +) -> Result { + let conn = Connection::open(path)?; + + let mut meta_out = Vec::new(); + let mut meta_stmt = conn.prepare("select name from sqlite_master where type='table'")?; + let mut meta_rows = meta_stmt.query([])?; + + while let Some(meta_row) = meta_rows.next()? { + let table_name: String = meta_row.get(0)?; + if tables.is_empty() || tables.contains(&table_name) { + let mut meta_dict = TaggedDictBuilder::new(tag.clone()); + let mut out = Vec::new(); + let mut table_stmt = conn.prepare(&format!("select * from [{}]", table_name))?; + let mut table_rows = table_stmt.query([])?; + while let Some(table_row) = table_rows.next()? { + out.push(convert_sqlite_row_to_nu_value(table_row, tag.clone())) + } + meta_dict.insert_value( + "table_name".to_string(), + UntaggedValue::Primitive(Primitive::String(table_name)).into_value(tag.clone()), + ); + meta_dict.insert_value( + "table_values", + UntaggedValue::Table(out).into_value(tag.clone()), + ); + meta_out.push(meta_dict.into_value()); + } + } + let tag = tag.into(); + Ok(UntaggedValue::Table(meta_out).into_value(tag)) +} + +fn convert_sqlite_row_to_nu_value(row: &Row, tag: impl Into + Clone) -> Value { + let mut collected = TaggedDictBuilder::new(tag.clone()); + for (i, c) in row.as_ref().column_names().iter().enumerate() { + collected.insert_value( + c.to_string(), + convert_sqlite_value_to_nu_value(row.get_ref_unwrap(i), tag.clone()), + ); + } + collected.into_value() +} + +fn convert_sqlite_value_to_nu_value(value: ValueRef, tag: impl Into + Clone) -> Value { + match value { + ValueRef::Null => { + UntaggedValue::Primitive(Primitive::String(String::from(""))).into_value(tag) + } + ValueRef::Integer(i) => UntaggedValue::int(i).into_value(tag), + ValueRef::Real(f) => { + let f = bigdecimal::BigDecimal::from_f64(f); + let tag = tag.into(); + let span = tag.span; + match f { + Some(d) => UntaggedValue::decimal(d).into_value(tag), + None => UntaggedValue::Error(ShellError::labeled_error( + "Can not convert f64 to big decimal", + "can not convert to decimal", + span, + )) + .into_value(tag), + } + } + ValueRef::Text(s) => { + // this unwrap is safe because we know the ValueRef is Text. + UntaggedValue::Primitive(Primitive::String(String::from_utf8_lossy(s).to_string())) + .into_value(tag) + } + ValueRef::Blob(u) => UntaggedValue::binary(u.to_owned()).into_value(tag), + } +} + +pub fn from_sqlite_bytes_to_value( + mut bytes: Vec, + tag: impl Into + Clone, + tables: Vec, +) -> Result { + // FIXME: should probably write a sqlite virtual filesystem + // that will allow us to use bytes as a file to avoid this + // write out, but this will require C code. Might be + // best done as a PR to rusqlite. + let mut tempfile = tempfile::NamedTempFile::new()?; + tempfile.write_all(bytes.as_mut_slice())?; + match convert_sqlite_file_to_nu_value(tempfile.path(), tag, tables) { + Ok(value) => Ok(value), + Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)), + } +} + +pub fn from_sqlite( + bytes: Vec, + name_tag: Tag, + tables: Vec, +) -> Result, ShellError> { + match from_sqlite_bytes_to_value(bytes, name_tag.clone(), tables) { + Ok(x) => match x { + Value { + value: UntaggedValue::Table(list), + .. + } => Ok(list.into_iter().map(ReturnSuccess::value).collect()), + _ => Ok(vec![ReturnSuccess::value(x)]), + }, + Err(_) => Err(ShellError::labeled_error( + "Could not parse as SQLite", + "input cannot be parsed as SQLite", + &name_tag, + )), + } +} diff --git a/crates/nu_plugin_from_sqlite/src/lib.rs b/crates/nu_plugin_from_sqlite/src/lib.rs new file mode 100644 index 0000000000..62e49fb460 --- /dev/null +++ b/crates/nu_plugin_from_sqlite/src/lib.rs @@ -0,0 +1,4 @@ +mod from_sqlite; +mod nu; + +pub use from_sqlite::FromSqlite; diff --git a/crates/nu_plugin_from_sqlite/src/main.rs b/crates/nu_plugin_from_sqlite/src/main.rs new file mode 100644 index 0000000000..26147638a5 --- /dev/null +++ b/crates/nu_plugin_from_sqlite/src/main.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_from_sqlite::FromSqlite; + +fn main() { + serve_plugin(&mut FromSqlite::new()) +} diff --git a/crates/nu_plugin_from_sqlite/src/nu/mod.rs b/crates/nu_plugin_from_sqlite/src/nu/mod.rs new file mode 100644 index 0000000000..f39463386e --- /dev/null +++ b/crates/nu_plugin_from_sqlite/src/nu/mod.rs @@ -0,0 +1,75 @@ +#[cfg(test)] +mod tests; + +use crate::FromSqlite; +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{CallInfo, Primitive, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value}; +use nu_source::Tag; + +// Adapted from crates/nu-command/src/commands/dataframe/utils.rs +fn convert_columns(columns: &[Value]) -> Result, ShellError> { + let res = columns + .iter() + .map(|value| match &value.value { + UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()), + _ => Err(ShellError::labeled_error( + "Incorrect column format", + "Only string as column name", + &value.tag, + )), + }) + .collect::, _>>()?; + + Ok(res) +} + +impl Plugin for FromSqlite { + fn config(&mut self) -> Result { + Ok(Signature::build("from sqlite") + .named( + "tables", + SyntaxShape::Table, + "Only convert specified tables", + Some('t'), + ) + .desc("Convert from sqlite binary into table") + .filter()) + } + + fn begin_filter(&mut self, call_info: CallInfo) -> Result, ShellError> { + self.name_tag = call_info.name_tag; + + if let Some(t) = call_info.args.get("tables") { + if let UntaggedValue::Table(columns) = t.value.clone() { + self.tables = convert_columns(columns.as_slice())?; + } + } + Ok(vec![]) + } + + fn filter(&mut self, input: Value) -> Result, ShellError> { + match input { + Value { + value: UntaggedValue::Primitive(Primitive::Binary(b)), + .. + } => { + self.state.extend_from_slice(&b); + } + Value { tag, .. } => { + return Err(ShellError::labeled_error_with_secondary( + "Expected binary from pipeline", + "requires binary input", + self.name_tag.clone(), + "value originates from here", + tag, + )); + } + } + Ok(vec![]) + } + + fn end_filter(&mut self) -> Result, ShellError> { + crate::from_sqlite::from_sqlite(self.state.clone(), Tag::unknown(), self.tables.clone()) + } +} diff --git a/crates/nu_plugin_from_sqlite/src/nu/tests.rs b/crates/nu_plugin_from_sqlite/src/nu/tests.rs new file mode 100644 index 0000000000..d14c19bee3 --- /dev/null +++ b/crates/nu_plugin_from_sqlite/src/nu/tests.rs @@ -0,0 +1 @@ +mod integration {} diff --git a/crates/nu_plugin_gstat/Cargo.toml b/crates/nu_plugin_gstat/Cargo.toml index bd862b0911..d356d2cd57 100644 --- a/crates/nu_plugin_gstat/Cargo.toml +++ b/crates/nu_plugin_gstat/Cargo.toml @@ -4,14 +4,14 @@ description = "A git status plugin for Nushell" edition = "2021" license = "MIT" name = "nu_plugin_gstat" -version = "0.1.0" +version = "0.59.0" [lib] doctest = false [dependencies] -nu-plugin = { path="../nu-plugin", version = "0.1.0" } -nu-protocol = { path="../nu-protocol", version = "0.1.0" } -nu-engine = { path="../nu-engine", version = "0.1.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-engine = { path="../nu-engine", version = "0.59.0" } git2 = "0.13.24" diff --git a/crates/nu_plugin_inc/Cargo.toml b/crates/nu_plugin_inc/Cargo.toml index b2dcbf24ff..c88bf08a1e 100644 --- a/crates/nu_plugin_inc/Cargo.toml +++ b/crates/nu_plugin_inc/Cargo.toml @@ -1,36 +1,16 @@ [package] authors = ["The Nu Project Contributors"] description = "A version incrementer plugin for Nushell" -<<<<<<< HEAD -edition = "2018" -license = "MIT" -name = "nu_plugin_inc" -version = "0.43.0" -======= edition = "2021" license = "MIT" name = "nu_plugin_inc" -version = "0.1.0" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce +version = "0.59.0" [lib] doctest = false [dependencies] -<<<<<<< HEAD -nu-errors = { path="../nu-errors", version = "0.43.0" } -nu-plugin = { path="../nu-plugin", version = "0.43.0" } -nu-protocol = { path="../nu-protocol", version = "0.43.0" } -nu-source = { path="../nu-source", version = "0.43.0" } -nu-test-support = { path="../nu-test-support", version = "0.43.0" } -nu-value-ext = { path="../nu-value-ext", version = "0.43.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0", features = ["plugin"]} semver = "0.11.0" - -[build-dependencies] -======= -nu-plugin = { path="../nu-plugin", version = "0.1.0" } -nu-protocol = { path="../nu-protocol", version = "0.1.0", features = ["plugin"]} - -semver = "0.11.0" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu_plugin_inc/src/inc.rs b/crates/nu_plugin_inc/src/inc.rs index e648caa024..9846a65388 100644 --- a/crates/nu_plugin_inc/src/inc.rs +++ b/crates/nu_plugin_inc/src/inc.rs @@ -1,12 +1,5 @@ -<<<<<<< HEAD -use nu_errors::ShellError; -use nu_protocol::{did_you_mean, ColumnPath, Primitive, ShellTypeName, UntaggedValue, Value}; -use nu_source::{span_for_spanned_list, HasSpan, SpannedItem, Tagged}; -use nu_value_ext::{get_data_by_column_path, ValueExt}; -======= use nu_plugin::LabeledError; use nu_protocol::{Span, Value}; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[derive(Debug, Eq, PartialEq)] pub enum Action { @@ -23,10 +16,6 @@ pub enum SemVerAction { #[derive(Default)] pub struct Inc { -<<<<<<< HEAD - pub field: Option>, -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce pub error: Option, pub action: Option, } @@ -36,25 +25,17 @@ impl Inc { Default::default() } -<<<<<<< HEAD - fn apply(&self, input: &str) -> UntaggedValue { -======= fn apply(&self, input: &str, head: Span) -> Value { ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce match &self.action { Some(Action::SemVerAction(act_on)) => { let mut ver = match semver::Version::parse(input) { Ok(parsed_ver) => parsed_ver, -<<<<<<< HEAD - Err(_) => return UntaggedValue::string(input.to_string()), -======= Err(_) => { return Value::String { val: input.to_string(), span: head, } } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }; match act_on { @@ -63,13 +44,6 @@ impl Inc { SemVerAction::Patch => ver.increment_patch(), } -<<<<<<< HEAD - UntaggedValue::string(ver.to_string()) - } - Some(Action::Default) | None => match input.parse::() { - Ok(v) => UntaggedValue::string((v + 1).to_string()), - Err(_) => UntaggedValue::string(input), -======= Value::String { val: ver.to_string(), span: head, @@ -84,7 +58,6 @@ impl Inc { val: input.to_string(), span: head, }, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }, } } @@ -109,76 +82,6 @@ impl Inc { "Usage: inc field [--major|--minor|--patch]" } -<<<<<<< HEAD - pub fn inc(&self, value: Value) -> Result { - match &value.value { - UntaggedValue::Primitive(Primitive::Int(i)) => { - Ok(UntaggedValue::int(i + 1).into_value(value.tag())) - } - UntaggedValue::Primitive(Primitive::Filesize(b)) => { - Ok(UntaggedValue::filesize(b + 1_u64).into_value(value.tag())) - } - UntaggedValue::Primitive(Primitive::String(ref s)) => { - Ok(self.apply(s).into_value(value.tag())) - } - UntaggedValue::Table(values) => { - if values.len() == 1 { - Ok(UntaggedValue::Table(vec![self.inc(values[0].clone())?]) - .into_value(value.tag())) - } else { - Err(ShellError::type_error( - "incrementable value", - value.type_name().spanned(value.span()), - )) - } - } - - UntaggedValue::Row(_) => match self.field { - Some(ref f) => { - let fields = f.clone(); - - let replace_for = get_data_by_column_path( - &value, - f, - move |obj_source, column_path_tried, _| match did_you_mean( - obj_source, - column_path_tried.as_string(), - ) { - Some(suggestions) => ShellError::labeled_error( - "Unknown column", - format!("did you mean '{}'?", suggestions[0]), - span_for_spanned_list(fields.iter().map(|p| p.span)), - ), - None => ShellError::labeled_error( - "Unknown column", - "row does not contain this column", - span_for_spanned_list(fields.iter().map(|p| p.span)), - ), - }, - ); - - let got = replace_for?; - let replacement = self.inc(got)?; - - value - .replace_data_at_column_path(f, replacement.value.into_untagged_value()) - .ok_or_else(|| { - ShellError::labeled_error( - "inc could not find field to replace", - "column name", - value.tag(), - ) - }) - } - None => Err(ShellError::untagged_runtime_error( - "inc needs a field when incrementing a column in a table", - )), - }, - _ => Err(ShellError::type_error( - "incrementable value", - value.type_name().spanned(value.span()), - )), -======= pub fn inc(&self, head: Span, value: &Value) -> Result { match value { Value::Int { val, span } => Ok(Value::Int { @@ -199,7 +102,6 @@ impl Inc { span: Some(head), }) } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } } @@ -207,17 +109,6 @@ impl Inc { #[cfg(test)] mod tests { mod semver { -<<<<<<< HEAD - use crate::inc::SemVerAction; - use crate::Inc; - use nu_test_support::value::string; - - #[test] - fn major() { - let mut inc = Inc::new(); - inc.for_semver(SemVerAction::Major); - assert_eq!(inc.apply("0.1.3"), string("1.0.0").value); -======= use nu_protocol::{Span, Value}; use crate::inc::SemVerAction; @@ -232,16 +123,10 @@ mod tests { let mut inc = Inc::new(); inc.for_semver(SemVerAction::Major); assert_eq!(inc.apply("0.1.3", Span::test_data()), expected) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] fn minor() { -<<<<<<< HEAD - let mut inc = Inc::new(); - inc.for_semver(SemVerAction::Minor); - assert_eq!(inc.apply("0.1.3"), string("0.2.0").value); -======= let expected = Value::String { val: "0.2.0".to_string(), span: Span::test_data(), @@ -249,16 +134,10 @@ mod tests { let mut inc = Inc::new(); inc.for_semver(SemVerAction::Minor); assert_eq!(inc.apply("0.1.3", Span::test_data()), expected) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] fn patch() { -<<<<<<< HEAD - let mut inc = Inc::new(); - inc.for_semver(SemVerAction::Patch); - assert_eq!(inc.apply("0.1.3"), string("0.1.4").value); -======= let expected = Value::String { val: "0.1.4".to_string(), span: Span::test_data(), @@ -266,7 +145,6 @@ mod tests { let mut inc = Inc::new(); inc.for_semver(SemVerAction::Patch); assert_eq!(inc.apply("0.1.3", Span::test_data()), expected) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } } diff --git a/crates/nu_plugin_inc/src/lib.rs b/crates/nu_plugin_inc/src/lib.rs index ad747ca042..e5428d8e6f 100644 --- a/crates/nu_plugin_inc/src/lib.rs +++ b/crates/nu_plugin_inc/src/lib.rs @@ -2,37 +2,3 @@ mod inc; mod nu; pub use inc::Inc; -<<<<<<< HEAD - -#[cfg(test)] -mod tests { - use super::Inc; - use crate::inc::Action; - use nu_protocol::Value; - use nu_value_ext::ValueExt; - - impl Inc { - pub fn expect_action(&self, action: Action) { - match &self.action { - Some(set) if set == &action => {} - Some(_) => panic!("\nUnexpected action"), - None => panic!("\nAction not found."), - } - } - - pub fn expect_field(&self, field: Value) { - let field = match field.as_column_path() { - Ok(column_path) => column_path, - Err(_) => panic!("\nExpected a ColumnPath",), - }; - - match &self.field { - Some(column_path) if column_path == &field => {} - Some(_) => panic!("\nUnexpected field."), - None => panic!("\nField not found."), - } - } - } -} -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce diff --git a/crates/nu_plugin_inc/src/main.rs b/crates/nu_plugin_inc/src/main.rs index e1d727fd66..9421c713ce 100644 --- a/crates/nu_plugin_inc/src/main.rs +++ b/crates/nu_plugin_inc/src/main.rs @@ -1,14 +1,6 @@ -<<<<<<< HEAD -use nu_plugin::serve_plugin; -use nu_plugin_inc::Inc; - -fn main() { - serve_plugin(&mut Inc::new()) -======= use nu_plugin::{serve_plugin, CapnpSerializer}; use nu_plugin_inc::Inc; fn main() { serve_plugin(&mut Inc::new(), CapnpSerializer {}) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/crates/nu_plugin_inc/src/nu/mod.rs b/crates/nu_plugin_inc/src/nu/mod.rs index 4571c7e626..21ea19befa 100644 --- a/crates/nu_plugin_inc/src/nu/mod.rs +++ b/crates/nu_plugin_inc/src/nu/mod.rs @@ -1,22 +1,3 @@ -<<<<<<< HEAD -#[cfg(test)] -mod tests; - -use crate::inc::{Action, SemVerAction}; -use crate::Inc; -use nu_errors::ShellError; -use nu_plugin::Plugin; -use nu_protocol::{ - CallInfo, Primitive, ReturnSuccess, ReturnValue, ShellTypeName, Signature, SyntaxShape, - UntaggedValue, Value, -}; -use nu_source::{HasSpan, SpannedItem}; -use nu_value_ext::ValueExt; - -impl Plugin for Inc { - fn config(&mut self) -> Result { - Ok(Signature::build("inc") -======= use crate::inc::SemVerAction; use crate::Inc; use nu_plugin::{EvaluatedCall, LabeledError, Plugin}; @@ -25,7 +6,6 @@ use nu_protocol::{Signature, Value}; impl Plugin for Inc { fn signature(&self) -> Vec { vec![Signature::build("inc") ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce .desc("Increment a value or version. Optionally use the column of a table.") .switch( "major", @@ -41,59 +21,6 @@ impl Plugin for Inc { "patch", "increment the patch version (eg 1.2.1 -> 1.2.2)", Some('p'), -<<<<<<< HEAD - ) - .rest("rest", SyntaxShape::ColumnPath, "the column(s) to update") - .filter()) - } - - fn begin_filter(&mut self, call_info: CallInfo) -> Result, ShellError> { - if call_info.args.has("major") { - self.for_semver(SemVerAction::Major); - } - if call_info.args.has("minor") { - self.for_semver(SemVerAction::Minor); - } - if call_info.args.has("patch") { - self.for_semver(SemVerAction::Patch); - } - - if let Some(args) = call_info.args.positional { - for arg in args { - match arg { - table @ Value { - value: UntaggedValue::Primitive(Primitive::ColumnPath(_)), - .. - } => { - self.field = Some(table.as_column_path()?); - } - value => { - return Err(ShellError::type_error( - "table", - value.type_name().spanned(value.span()), - )) - } - } - } - } - - if self.action.is_none() { - self.action = Some(Action::Default); - } - - match &self.error { - Some(reason) => Err(ShellError::untagged_runtime_error(format!( - "{}: {}", - reason, - Inc::usage() - ))), - None => Ok(vec![]), - } - } - - fn filter(&mut self, input: Value) -> Result, ShellError> { - Ok(vec![ReturnSuccess::value(self.inc(input)?)]) -======= )] } @@ -118,6 +45,5 @@ impl Plugin for Inc { } self.inc(call.head, input) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } diff --git a/crates/nu_plugin_match/Cargo.toml b/crates/nu_plugin_match/Cargo.toml new file mode 100644 index 0000000000..d678667a3c --- /dev/null +++ b/crates/nu_plugin_match/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "A regex match plugin for Nushell" +edition = "2018" +license = "MIT" +name = "nu_plugin_match" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +regex = "1.4.3" + +[build-dependencies] diff --git a/crates/nu_plugin_match/src/lib.rs b/crates/nu_plugin_match/src/lib.rs new file mode 100644 index 0000000000..8def363497 --- /dev/null +++ b/crates/nu_plugin_match/src/lib.rs @@ -0,0 +1,4 @@ +mod match_; +mod nu; + +pub use match_::Match; diff --git a/crates/nu_plugin_match/src/main.rs b/crates/nu_plugin_match/src/main.rs new file mode 100644 index 0000000000..2023f39635 --- /dev/null +++ b/crates/nu_plugin_match/src/main.rs @@ -0,0 +1,7 @@ +use nu_plugin::serve_plugin; +use nu_plugin_match::Match; + +fn main() -> Result<(), Box> { + serve_plugin(&mut Match::new()?); + Ok(()) +} diff --git a/crates/nu_plugin_match/src/match_.rs b/crates/nu_plugin_match/src/match_.rs new file mode 100644 index 0000000000..b90c5e2dca --- /dev/null +++ b/crates/nu_plugin_match/src/match_.rs @@ -0,0 +1,18 @@ +use regex::Regex; + +pub struct Match { + pub column: String, + pub regex: Regex, + pub invert: bool, +} + +impl Match { + #[allow(clippy::trivial_regex)] + pub fn new() -> Result> { + Ok(Match { + column: String::new(), + regex: Regex::new("")?, + invert: false, + }) + } +} diff --git a/crates/nu_plugin_match/src/nu/mod.rs b/crates/nu_plugin_match/src/nu/mod.rs new file mode 100644 index 0000000000..5bf7abaad9 --- /dev/null +++ b/crates/nu_plugin_match/src/nu/mod.rs @@ -0,0 +1,124 @@ +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{ + CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value, +}; + +use crate::Match; +use regex::Regex; + +impl Plugin for Match { + fn config(&mut self) -> Result { + Ok(Signature::build("match") + .desc("Filter rows by Regex pattern.") + .required("member", SyntaxShape::String, "the column name to match") + .required("regex", SyntaxShape::String, "the regex to match with") + .switch("insensitive", "case-insensitive search", Some('i')) + .switch( + "multiline", + "multi-line mode: ^ and $ match begin/end of line", + Some('m'), + ) + .switch( + "dotall", + "dotall mode: allow a dot . to match newline character \\n", + Some('s'), + ) + .switch("invert", "invert the match", Some('v')) + .filter()) + } + + fn begin_filter(&mut self, call_info: CallInfo) -> Result, ShellError> { + let insensitive = call_info.args.has("insensitive"); + let multiline = call_info.args.has("multiline"); + let dotall = call_info.args.has("dotall"); + self.invert = call_info.args.has("invert"); + if let Some(args) = call_info.args.positional { + match &args[0] { + Value { + value: UntaggedValue::Primitive(Primitive::String(s)), + .. + } => { + self.column = s.clone(); + } + Value { tag, .. } => { + return Err(ShellError::labeled_error( + "Unrecognized type in params", + "value", + tag, + )); + } + } + let flags = match (insensitive, multiline, dotall) { + (false, false, false) => "", + (true, false, false) => "(?i)", + (false, true, false) => "(?m)", + (false, false, true) => "(?s)", + (true, true, false) => "(?im)", + (true, false, true) => "(?is)", + (false, true, true) => "(?ms)", + (true, true, true) => "(?ims)", + } + .to_owned(); + match &args[1] { + Value { + value: UntaggedValue::Primitive(Primitive::String(s)), + tag, + } => { + self.regex = Regex::new(&(flags + s)).map_err(|_| { + ShellError::labeled_error( + "Internal error while creating regex", + "internal error created by pattern", + tag, + ) + })?; + } + Value { tag, .. } => { + return Err(ShellError::labeled_error( + "Unrecognized type in params", + "unexpected value", + tag, + )); + } + } + } + + Ok(vec![]) + } + + fn filter(&mut self, input: Value) -> Result, ShellError> { + let flag: bool; + match &input { + Value { + value: UntaggedValue::Row(dict), + tag, + } => { + if let Some(val) = dict.entries.get(&self.column) { + if let Ok(s) = val.as_string() { + flag = self.regex.is_match(&s); + } else { + return Err(ShellError::labeled_error( + "expected string", + "value", + val.tag(), + )); + } + } else { + return Err(ShellError::labeled_error( + format!("column not in row! {:?} {:?}", &self.column, dict), + "row", + tag, + )); + } + } + Value { tag, .. } => { + return Err(ShellError::labeled_error("Expected row", "value", tag)); + } + } + if flag ^ self.invert { + Ok(vec![Ok(ReturnSuccess::Value(input))]) + } else { + Ok(vec![]) + } + } +} diff --git a/crates/nu_plugin_query/Cargo.toml b/crates/nu_plugin_query/Cargo.toml index 188dce7b3f..7f7758f184 100644 --- a/crates/nu_plugin_query/Cargo.toml +++ b/crates/nu_plugin_query/Cargo.toml @@ -4,15 +4,15 @@ description = "A set of query commands for Nushell" edition = "2021" license = "MIT" name = "nu_plugin_query" -version = "0.1.0" +version = "0.59.0" [lib] doctest = false [dependencies] -nu-plugin = { path="../nu-plugin", version = "0.1.0" } -nu-protocol = { path="../nu-protocol", version = "0.1.0" } -nu-engine = { path="../nu-engine", version = "0.1.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-engine = { path="../nu-engine", version = "0.59.0" } gjson = "0.8.0" scraper = "0.12.0" sxd-document = "0.3.2" diff --git a/crates/nu_plugin_s3/Cargo.toml b/crates/nu_plugin_s3/Cargo.toml new file mode 100644 index 0000000000..6bf8ac4e06 --- /dev/null +++ b/crates/nu_plugin_s3/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "An S3 plugin for Nushell" +edition = "2018" +license = "MIT" +name = "nu_plugin_s3" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +futures = { version="0.3.12", features=["compat", "io-compat"] } +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-source = { path="../nu-source", version = "0.59.0" } +s3handler = "0.7.5" + +[build-dependencies] diff --git a/crates/nu_plugin_s3/README.md b/crates/nu_plugin_s3/README.md new file mode 100644 index 0000000000..60ffb3320a --- /dev/null +++ b/crates/nu_plugin_s3/README.md @@ -0,0 +1,9 @@ +Nu Plugin S3 +--- + +An S3 plugin for nu shell, it can load the content of S3 objects and convert into table + +#### Snapshot +In following example, the return content from httpbin is saved before as an object in AWS S3. +![snapshot](https://raw.githubusercontent.com/yanganto/nu_plugin_s3/master/demo.png) + diff --git a/crates/nu_plugin_s3/demo.png b/crates/nu_plugin_s3/demo.png new file mode 100644 index 0000000000000000000000000000000000000000..8fd2a4162d5683d5bfa072a0d1d85cdab64389b8 GIT binary patch literal 81084 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

0e7U0M@Jkb z5DyRLiu&aPS14H}C1JhmLqo3@+AF=K%>ZEdj@be+_h~6dQ4xf)dIk??S!F)hVfCl) zIy{P}xC+vh<6Sw!B)ygXp=6FFyDrfbDB{OQ?f0E9K@qQ%UaL&}=Eu24GK zbhr_SHQ+qmUr=ShaoSA~G_LP8qBOFaUY6W!m2xYEH4iy8%Rh0OZP0NtqlLCneVH;DE=j|z2L&ZXlx%VpcKF21OxDEM zqtILa3(2-8o`2v)Q%#cQa%zy%VNQf}qnieDKSzKBzwG3x)E_A1sZ&S9Hl;s%V1O4t z2L02P`tiAc*-6s_=jq7jm6f72Qj(It{cZ025tvuszsC*d=1^Atha2@9;2rSSIHxR6 z1CvLU*9jS%+2jmG)PJ($r%qY^uQC2U$?#YI+rJ*aF7Y?*`d>cWUq_z$Kb*KctWipJ zKoWJ|$xVoLKHmO^y6fE1(iQ4C3q8H5fq|!YvraR;In6Xxbso$~Ym?dUgU)5Pc6Rl! z{v?fxGMJh&eX+;&>!9DCQ%mQyT>O}bKEJ~)j|1u3vC82${{FO&Qy%>7vw7+i|G%8V v%TE2{H$C<7%s, + pub tag: Tag, + pub has_raw: bool, + pub config: CredentialConfig, +} + +impl Handler { + pub fn new() -> Handler { + Handler { + tag: Tag::unknown(), + config: CredentialConfig { + host: String::new(), + access_key: String::new(), + secret_key: String::new(), + user: None, + region: None, + s3_type: None, + secure: None, + }, + resource: None, + has_raw: false, + } + } + + pub fn setup(&mut self, call_info: CallInfo) -> ReturnValue { + self.resource = { + let r = call_info.args.nth(0).ok_or_else(|| { + ShellError::labeled_error( + "No obj or directory specified", + "for command", + &call_info.name_tag, + ) + })?; + Some(r.clone()) + }; + self.tag = call_info.name_tag.clone(); + self.has_raw = call_info.args.has("raw"); + + if let Some(e) = call_info.args.get("endpoint") { + self.config.host = e.as_string()? + } else { + return Err(ShellError::labeled_error( + "No endpoint provided", + "for command", + &call_info.name_tag, + )); + } + + if let Some(access_key) = call_info.args.get("access_key") { + self.config.access_key = access_key.as_string()? + } else { + return Err(ShellError::labeled_error( + "No access key provided", + "for command", + &call_info.name_tag, + )); + } + + if let Some(secret_key) = call_info.args.get("secret_key") { + self.config.secret_key = secret_key.as_string()? + } else { + return Err(ShellError::labeled_error( + "No secret key provided", + "for command", + &call_info.name_tag, + )); + } + + if let Some(region) = call_info.args.get("region") { + self.config.region = Some(region.as_string()?) + } + + ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value()) + } +} + +impl Default for Handler { + fn default() -> Self { + Self::new() + } +} + +pub async fn s3_helper(resource: &Value, has_raw: bool, config: &CredentialConfig) -> ReturnValue { + let resource_str = resource.as_string()?; + let mut handler = S3Handler::from(config); + let (output, content_type) = handler + .cat(&resource_str) + .map_err(|e| ShellError::unexpected(e.to_string()))?; + + let extension = if has_raw { + None + } else { + fn get_accept_ext(s: String) -> Option { + if s.contains("json") { + Some("json".to_string()) + } else if s.contains("xml") { + Some("xml".to_string()) + } else if s.contains("svg") { + Some("svg".to_string()) + } else if s.contains("html") { + Some("html".to_string()) + } else { + None + } + } + // If the extension could not provide when uploading, + // try to use the resource extension. + content_type.and_then(get_accept_ext).or_else(|| { + resource_str + .split('.') + .last() + .map(String::from) + .and_then(get_accept_ext) + }) + }; + + if let Some(e) = extension { + Ok(ReturnSuccess::Action(CommandAction::AutoConvert( + UntaggedValue::string(output).into_value(Tag { + span: resource.tag.span, + anchor: Some(AnchorLocation::Url(resource_str)), + }), + e, + ))) + } else { + ReturnSuccess::value(UntaggedValue::string(output)) + } +} diff --git a/crates/nu_plugin_s3/src/lib.rs b/crates/nu_plugin_s3/src/lib.rs new file mode 100644 index 0000000000..c906216399 --- /dev/null +++ b/crates/nu_plugin_s3/src/lib.rs @@ -0,0 +1,4 @@ +pub mod handler; +mod nu; + +pub use handler::Handler; diff --git a/crates/nu_plugin_s3/src/main.rs b/crates/nu_plugin_s3/src/main.rs new file mode 100644 index 0000000000..e3d0a58412 --- /dev/null +++ b/crates/nu_plugin_s3/src/main.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_s3::handler; + +fn main() { + serve_plugin(&mut handler::Handler::new()) +} diff --git a/crates/nu_plugin_s3/src/nu/mod.rs b/crates/nu_plugin_s3/src/nu/mod.rs new file mode 100644 index 0000000000..d93aadf79a --- /dev/null +++ b/crates/nu_plugin_s3/src/nu/mod.rs @@ -0,0 +1,60 @@ +use futures::executor::block_on; +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{CallInfo, ReturnValue, Signature, SyntaxShape}; + +use crate::handler; +use crate::handler::s3_helper; + +impl Plugin for handler::Handler { + fn config(&mut self) -> Result { + Ok(Signature::build("s3") + .desc("Load S3 resource into a cell, convert to table if possible (avoid by appending '--raw' or '-R')") + .required( + "RESOURCE", + SyntaxShape::String, + "the RESOURCE to fetch the contents from", + ) + .named( + "endpoint", + SyntaxShape::Any, + "the endpoint info for the S3 resource, i.g., s3.ap-northeast-1.amazonaws.com or 10.1.1.1", + Some('e'), + ) + .named( + "access_key", + SyntaxShape::Any, + "the access key when authenticating", + Some('a'), + ) + .named( + "secret_key", + SyntaxShape::Any, + "the secret key when authenticating", + Some('s'), + ) + .named( + "region", + SyntaxShape::Any, + "the region of the resource, default will use us-east-1", + Some('r'), + ) + .switch("raw", "fetch contents as text rather than a table", Some('R')) + .filter()) + } + + fn begin_filter(&mut self, callinfo: CallInfo) -> Result, ShellError> { + self.setup(callinfo)?; + Ok(vec![block_on(s3_helper( + &self.resource.clone().ok_or_else(|| { + ShellError::labeled_error( + "internal error: resource not set", + "resource not set", + &self.tag, + ) + })?, + self.has_raw, + &self.config, + ))]) + } +} diff --git a/crates/nu_plugin_start/Cargo.toml b/crates/nu_plugin_start/Cargo.toml new file mode 100644 index 0000000000..2daa1b5f9c --- /dev/null +++ b/crates/nu_plugin_start/Cargo.toml @@ -0,0 +1,26 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "A plugin to open files/URLs directly from Nushell" +edition = "2018" +license = "MIT" +name = "nu_plugin_start" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +glob = "0.3.0" +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-source = { path="../nu-source", version = "0.59.0" } +url = "2.2.0" +webbrowser = "0.5.5" + +[target.'cfg(windows)'.dependencies] +open = "1.4.0" + +[build-dependencies] +nu-errors = { version = "0.59.0", path="../nu-errors" } +nu-source = { version = "0.59.0", path="../nu-source" } diff --git a/crates/nu_plugin_start/src/lib.rs b/crates/nu_plugin_start/src/lib.rs new file mode 100644 index 0000000000..de341633d3 --- /dev/null +++ b/crates/nu_plugin_start/src/lib.rs @@ -0,0 +1,4 @@ +mod nu; +mod start; + +pub use start::Start; diff --git a/crates/nu_plugin_start/src/main.rs b/crates/nu_plugin_start/src/main.rs new file mode 100644 index 0000000000..43ef421b8e --- /dev/null +++ b/crates/nu_plugin_start/src/main.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_start::Start; + +fn main() { + serve_plugin(&mut Start::new()); +} diff --git a/crates/nu_plugin_start/src/nu/mod.rs b/crates/nu_plugin_start/src/nu/mod.rs new file mode 100644 index 0000000000..594fe3430a --- /dev/null +++ b/crates/nu_plugin_start/src/nu/mod.rs @@ -0,0 +1,28 @@ +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{CallInfo, ReturnValue, Signature, SyntaxShape}; + +use crate::start::Start; + +impl Plugin for Start { + fn config(&mut self) -> Result { + Ok(Signature::build("start") + .desc("Opens each file/directory/URL using the default application") + .rest( + "rest", + SyntaxShape::String, + "files/urls/directories to open", + ) + .named( + "application", + SyntaxShape::String, + "Specifies the application used for opening the files/directories/urls", + Some('a'), + ) + .filter()) + } + fn begin_filter(&mut self, call_info: CallInfo) -> Result, ShellError> { + self.parse(call_info)?; + self.exec().map(|_| Vec::new()) + } +} diff --git a/crates/nu_plugin_start/src/start.rs b/crates/nu_plugin_start/src/start.rs new file mode 100644 index 0000000000..068c2abb33 --- /dev/null +++ b/crates/nu_plugin_start/src/start.rs @@ -0,0 +1,260 @@ +use nu_errors::ShellError; +use nu_protocol::{CallInfo, Value}; +use nu_source::{Tag, Tagged, TaggedItem}; +use std::path::Path; +#[cfg(not(target_os = "windows"))] +use std::process::{Command, Stdio}; + +#[derive(Default)] +pub struct Start { + pub tag: Tag, + pub filenames: Vec>, + pub application: Option, +} + +impl Start { + pub fn new() -> Start { + Start { + tag: Tag::unknown(), + filenames: vec![], + application: None, + } + } + + pub fn parse(&mut self, call_info: CallInfo) -> Result<(), ShellError> { + self.tag = call_info.name_tag.clone(); + self.parse_input_parameters(&call_info)?; + self.parse_application(&call_info); + Ok(()) + } + + fn add_filename(&mut self, filename: Tagged) -> Result<(), ShellError> { + if Path::new(&filename.item).exists() || url::Url::parse(&filename.item).is_ok() { + self.filenames.push(filename); + Ok(()) + } else { + Err(ShellError::labeled_error( + format!("The file '{}' does not exist", filename.item), + "doesn't exist", + filename.tag, + )) + } + } + + fn glob_to_values(&self, value: &Value) -> Result>, ShellError> { + let mut result = vec![]; + match glob::glob(&value.as_string()?) { + Ok(paths) => { + for path_result in paths { + match path_result { + Ok(path) => result + .push(path.to_string_lossy().to_string().tagged(value.tag.clone())), + Err(glob_error) => { + return Err(ShellError::labeled_error( + glob_error.to_string(), + "glob error", + value.tag.clone(), + )); + } + } + } + } + Err(pattern_error) => { + return Err(ShellError::labeled_error( + pattern_error.to_string(), + "invalid pattern", + value.tag.clone(), + )) + } + } + + Ok(result) + } + + fn parse_input_parameters(&mut self, call_info: &CallInfo) -> Result<(), ShellError> { + let candidates = match &call_info.args.positional { + Some(values) => { + let mut result = vec![]; + + for value in values { + let val_str = value.as_string(); + match val_str { + Ok(s) => { + if s.to_ascii_lowercase().starts_with("http") + || s.to_ascii_lowercase().starts_with("https") + { + if webbrowser::open(&s).is_ok() { + result.push("http/web".to_string().tagged_unknown()) + } else { + return Err(ShellError::labeled_error( + &format!("error opening {}", &s), + "error opening url", + self.tag.span, + )); + } + } else { + let res = self.glob_to_values(value)?; + result.extend(res); + } + } + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + "no input given", + self.tag.span, + )); + } + } + } + + if result.is_empty() { + return Err(ShellError::labeled_error( + "No input given", + "no input given", + self.tag.span, + )); + } + result + } + None => { + return Err(ShellError::labeled_error( + "No input given", + "no input given", + self.tag.span, + )) + } + }; + + for candidate in candidates { + if !candidate.contains("http/web") { + self.add_filename(candidate)?; + } + } + + Ok(()) + } + + fn parse_application(&mut self, call_info: &CallInfo) { + self.application = if let Some(app) = call_info.args.get("application") { + match app.as_string() { + Ok(name) => Some(name), + Err(_) => None, + } + } else { + None + }; + } + + #[cfg(target_os = "macos")] + pub fn exec(&mut self) -> Result<(), ShellError> { + let mut args = vec![]; + args.append( + &mut self + .filenames + .iter() + .map(|x| x.item.clone()) + .collect::>(), + ); + + if let Some(app_name) = &self.application { + args.append(&mut vec![String::from("-a"), app_name.to_string()]); + } + exec_cmd("open", &args, self.tag.clone()) + } + + #[cfg(target_os = "windows")] + pub fn exec(&mut self) -> Result<(), ShellError> { + if let Some(app_name) = &self.application { + for file in &self.filenames { + match open::with(&file.item, app_name) { + Ok(_) => continue, + Err(_) => { + return Err(ShellError::labeled_error( + "Failed to open file with specified application", + "can't open with specified application", + file.tag.span, + )) + } + } + } + } else { + for file in &self.filenames { + match open::that(&file.item) { + Ok(_) => continue, + Err(_) => { + return Err(ShellError::labeled_error( + "Failed to open file with default application", + "can't open with default application", + file.tag.span, + )) + } + } + } + } + Ok(()) + } + + #[cfg(not(any(target_os = "windows", target_os = "macos")))] + pub fn exec(&mut self) -> Result<(), ShellError> { + let mut args = vec![]; + args.append( + &mut self + .filenames + .iter() + .map(|x| x.item.clone()) + .collect::>(), + ); + + if let Some(app_name) = &self.application { + exec_cmd(app_name, &args, self.tag.clone()) + } else { + for cmd in ["xdg-open", "gnome-open", "kde-open", "wslview"] { + if exec_cmd(cmd, &args, self.tag.clone()).is_err() { + continue; + } else { + return Ok(()); + } + } + Err(ShellError::labeled_error( + "Failed to open file(s) with xdg-open. gnome-open, kde-open, and wslview", + "failed to open xdg-open. gnome-open, kde-open, and wslview", + self.tag.span, + )) + } + } +} + +#[cfg(not(target_os = "windows"))] +fn exec_cmd(cmd: &str, args: &[String], tag: Tag) -> Result<(), ShellError> { + if args.is_empty() { + return Err(ShellError::labeled_error( + "No file(s) or application provided", + "no file(s) or application provided", + tag, + )); + } + let status = match Command::new(cmd) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .args(args) + .status() + { + Ok(exit_code) => exit_code, + Err(_) => { + return Err(ShellError::labeled_error( + "Failed to run native open syscall", + "failed to run native open call", + tag, + )) + } + }; + if status.success() { + Ok(()) + } else { + Err(ShellError::labeled_error( + "Failed to run start. Hint: The file(s)/application may not exist", + "failed to run", + tag, + )) + } +} diff --git a/crates/nu_plugin_to_bson/Cargo.toml b/crates/nu_plugin_to_bson/Cargo.toml new file mode 100644 index 0000000000..3070efedbf --- /dev/null +++ b/crates/nu_plugin_to_bson/Cargo.toml @@ -0,0 +1,23 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "A converter plugin to the bson format for Nushell" +edition = "2018" +license = "MIT" +name = "nu_plugin_to_bson" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +bson = { version = "2.0.1", features = [ "chrono-0_4" ] } +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-source = { path="../nu-source", version = "0.59.0" } +num-traits = "0.2.14" + +[features] +dataframe = ["nu-protocol/dataframe"] + +[build-dependencies] diff --git a/crates/nu_plugin_to_bson/src/lib.rs b/crates/nu_plugin_to_bson/src/lib.rs new file mode 100644 index 0000000000..9193d10c5e --- /dev/null +++ b/crates/nu_plugin_to_bson/src/lib.rs @@ -0,0 +1,4 @@ +mod nu; +mod to_bson; + +pub use to_bson::ToBson; diff --git a/crates/nu_plugin_to_bson/src/main.rs b/crates/nu_plugin_to_bson/src/main.rs new file mode 100644 index 0000000000..47d3f0468c --- /dev/null +++ b/crates/nu_plugin_to_bson/src/main.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_to_bson::ToBson; + +fn main() { + serve_plugin(&mut ToBson::new()) +} diff --git a/crates/nu_plugin_to_bson/src/nu/mod.rs b/crates/nu_plugin_to_bson/src/nu/mod.rs new file mode 100644 index 0000000000..515fafe212 --- /dev/null +++ b/crates/nu_plugin_to_bson/src/nu/mod.rs @@ -0,0 +1,25 @@ +#[cfg(test)] +mod tests; + +use crate::ToBson; +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{ReturnValue, Signature, Value}; +use nu_source::Tag; + +impl Plugin for ToBson { + fn config(&mut self) -> Result { + Ok(Signature::build("to bson") + .desc("Convert table into .bson binary") + .filter()) + } + + fn filter(&mut self, input: Value) -> Result, ShellError> { + self.state.push(input); + Ok(vec![]) + } + + fn end_filter(&mut self) -> Result, ShellError> { + Ok(crate::to_bson::to_bson(self.state.clone(), Tag::unknown())) + } +} diff --git a/crates/nu_plugin_to_bson/src/nu/tests.rs b/crates/nu_plugin_to_bson/src/nu/tests.rs new file mode 100644 index 0000000000..d14c19bee3 --- /dev/null +++ b/crates/nu_plugin_to_bson/src/nu/tests.rs @@ -0,0 +1 @@ +mod integration {} diff --git a/crates/nu_plugin_to_bson/src/to_bson.rs b/crates/nu_plugin_to_bson/src/to_bson.rs new file mode 100644 index 0000000000..b4bf79c5e7 --- /dev/null +++ b/crates/nu_plugin_to_bson/src/to_bson.rs @@ -0,0 +1,300 @@ +use bson::{oid::ObjectId, spec::BinarySubtype, Bson, Document}; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{ + Dictionary, Primitive, ReturnSuccess, ReturnValue, SpannedTypeName, UnspannedPathMember, + UntaggedValue, Value, +}; +use nu_source::{Tag, TaggedItem}; +use num_traits::ToPrimitive; +use std::convert::TryInto; + +#[derive(Default)] +pub struct ToBson { + pub state: Vec, +} + +impl ToBson { + pub fn new() -> ToBson { + ToBson { state: vec![] } + } +} + +pub fn value_to_bson_value(v: &Value) -> Result { + Ok(match &v.value { + UntaggedValue::Primitive(Primitive::Boolean(b)) => Bson::Boolean(*b), + // FIXME: What about really big decimals? + UntaggedValue::Primitive(Primitive::Filesize(decimal)) => Bson::Double( + (decimal) + .to_f64() + .expect("Unimplemented BUG: What about big decimals?"), + ), + UntaggedValue::Primitive(Primitive::Duration(i)) => Bson::String(i.to_string()), + UntaggedValue::Primitive(Primitive::Date(d)) => { + Bson::DateTime(bson::DateTime::from_chrono(*d)) + } + UntaggedValue::Primitive(Primitive::EndOfStream) => Bson::Null, + UntaggedValue::Primitive(Primitive::BeginningOfStream) => Bson::Null, + UntaggedValue::Primitive(Primitive::Decimal(d)) => { + Bson::Double(d.to_f64().ok_or_else(|| { + ShellError::labeled_error( + "Could not convert value to decimal", + "could not convert to decimal", + &v.tag, + ) + })?) + } + UntaggedValue::Primitive(Primitive::Int(i)) => Bson::Int64(*i), + UntaggedValue::Primitive(Primitive::BigInt(i)) => { + Bson::Int64(i.tagged(&v.tag).coerce_into("converting to BSON")?) + } + UntaggedValue::Primitive(Primitive::Nothing) => Bson::Null, + UntaggedValue::Primitive(Primitive::String(s)) => Bson::String(s.clone()), + UntaggedValue::Primitive(Primitive::ColumnPath(path)) => Bson::Array( + path.iter() + .map(|x| match &x.unspanned { + UnspannedPathMember::String(string) => Ok(Bson::String(string.clone())), + UnspannedPathMember::Int(int) => Ok(Bson::Int64(*int)), + }) + .collect::, ShellError>>()?, + ), + UntaggedValue::Primitive(Primitive::GlobPattern(p)) => Bson::String(p.clone()), + UntaggedValue::Primitive(Primitive::FilePath(s)) => Bson::String(s.display().to_string()), + UntaggedValue::Table(l) => Bson::Array( + l.iter() + .map(value_to_bson_value) + .collect::>()?, + ), + UntaggedValue::Block(_) | UntaggedValue::Primitive(Primitive::Range(_)) => Bson::Null, + #[cfg(feature = "dataframe")] + UntaggedValue::DataFrame(_) | UntaggedValue::FrameStruct(_) => Bson::Null, + UntaggedValue::Error(e) => return Err(e.clone()), + UntaggedValue::Primitive(Primitive::Binary(b)) => Bson::Binary(bson::Binary { + subtype: BinarySubtype::Generic, + bytes: b.clone(), + }), + UntaggedValue::Row(o) => object_value_to_bson(o)?, + // TODO Impelmenting Bson::Undefined, Bson::MaxKey, Bson::MinKey and Bson::DbPointer + // These Variants weren't present in the previous version. + }) +} + +// object_value_to_bson handles all Objects, even those that correspond to special +// types (things like regex or javascript code). +fn object_value_to_bson(o: &Dictionary) -> Result { + let mut it = o.entries.iter(); + if it.len() > 2 { + return generic_object_value_to_bson(o); + } + match it.next() { + Some((regex, tagged_regex_value)) if regex == "$regex" => match it.next() { + Some((options, tagged_opts_value)) if options == "$options" => { + let r: Result = tagged_regex_value.try_into(); + let opts: Result = tagged_opts_value.try_into(); + match (r, opts) { + (Ok(pattern), Ok(options)) => { + Ok(Bson::RegularExpression(bson::Regex { pattern, options })) + } + _ => generic_object_value_to_bson(o), + } + } + _ => generic_object_value_to_bson(o), + }, + Some((javascript, tagged_javascript_value)) if javascript == "$javascript" => { + match it.next() { + Some((scope, tagged_scope_value)) if scope == "$scope" => { + let js: Result = tagged_javascript_value.try_into(); + let s: Result<&Dictionary, _> = tagged_scope_value.try_into(); + + match (js, s) { + (Ok(code), Ok(s)) => { + if let Bson::Document(scope) = object_value_to_bson(s)? { + Ok(Bson::JavaScriptCodeWithScope( + bson::JavaScriptCodeWithScope { code, scope }, + )) + } else { + generic_object_value_to_bson(o) + } + } + _ => generic_object_value_to_bson(o), + } + } + None => { + let js: Result = tagged_javascript_value.try_into(); + + match js { + Err(_) => generic_object_value_to_bson(o), + Ok(v) => Ok(Bson::JavaScriptCode(v)), + } + } + _ => generic_object_value_to_bson(o), + } + } + Some((timestamp, tagged_timestamp_value)) if timestamp == "$timestamp" => { + let ts: Result = tagged_timestamp_value.try_into(); + if let Ok(time) = ts { + Ok(Bson::Timestamp(bson::Timestamp { + time: time as u32, + increment: Default::default(), + })) + } else { + generic_object_value_to_bson(o) + } + } + Some((binary_subtype, tagged_binary_subtype_value)) + if binary_subtype == "$binary_subtype" => + { + match it.next() { + Some((binary, tagged_bin_value)) if binary == "$binary" => { + let bst = get_binary_subtype(tagged_binary_subtype_value); + let bin: Result, _> = tagged_bin_value.try_into(); + + match (bin, bst) { + (Ok(bin), Ok(subtype)) => Ok(Bson::Binary(bson::Binary { + subtype, + bytes: bin, + })), + _ => generic_object_value_to_bson(o), + } + } + _ => generic_object_value_to_bson(o), + } + } + Some((object_id, tagged_object_id_value)) if object_id == "$object_id" => { + let obj_id: Result = tagged_object_id_value.try_into(); + + if let Ok(obj_id) = obj_id { + let obj_id = ObjectId::parse_str(&obj_id); + + if let Ok(obj_id) = obj_id { + Ok(Bson::ObjectId(obj_id)) + } else { + generic_object_value_to_bson(o) + } + } else { + generic_object_value_to_bson(o) + } + } + Some((symbol, tagged_symbol_value)) if symbol == "$symbol" => { + let sym: Result = tagged_symbol_value.try_into(); + if let Ok(sym) = sym { + Ok(Bson::Symbol(sym)) + } else { + generic_object_value_to_bson(o) + } + } + _ => generic_object_value_to_bson(o), + } +} + +fn get_binary_subtype(tagged_value: &Value) -> Result { + match &tagged_value.value { + UntaggedValue::Primitive(Primitive::String(s)) => Ok(match s.as_ref() { + "generic" => BinarySubtype::Generic, + "function" => BinarySubtype::Function, + "binary_old" => BinarySubtype::BinaryOld, + "uuid_old" => BinarySubtype::UuidOld, + "uuid" => BinarySubtype::Uuid, + "md5" => BinarySubtype::Md5, + _ => unreachable!(), + }), + UntaggedValue::Primitive(Primitive::BigInt(i)) => Ok(BinarySubtype::UserDefined( + i.tagged(&tagged_value.tag) + .coerce_into("converting to BSON binary subtype")?, + )), + _ => Err(ShellError::type_error( + "bson binary", + tagged_value.spanned_type_name(), + )), + } +} + +// generic_object_value_bson handles any Object that does not +// correspond to a special bson type (things like regex or javascript code). +fn generic_object_value_to_bson(o: &Dictionary) -> Result { + let mut doc = Document::new(); + for (k, v) in &o.entries { + doc.insert(k.clone(), value_to_bson_value(v)?); + } + Ok(Bson::Document(doc)) +} + +fn shell_encode_document(writer: &mut Vec, doc: Document, tag: Tag) -> Result<(), ShellError> { + match doc.to_writer(writer) { + Err(e) => Err(ShellError::labeled_error( + format!("Failed to encode document due to: {:?}", e), + "requires BSON-compatible document", + tag, + )), + _ => Ok(()), + } +} + +fn bson_value_to_bytes(bson: Bson, tag: Tag) -> Result, ShellError> { + let mut out = Vec::new(); + match bson { + Bson::Array(a) => { + for v in a { + match v { + Bson::Document(d) => shell_encode_document(&mut out, d, tag.clone())?, + _ => { + return Err(ShellError::labeled_error( + format!("All top level values must be Documents, got {:?}", v), + "requires BSON-compatible document", + &tag, + )) + } + } + } + } + Bson::Document(d) => shell_encode_document(&mut out, d, tag)?, + _ => { + return Err(ShellError::labeled_error( + format!("All top level values must be Documents, got {:?}", bson), + "requires BSON-compatible document", + tag, + )) + } + } + Ok(out) +} + +pub fn to_bson(input: Vec, name_tag: Tag) -> Vec { + let name_span = name_tag.span; + + let to_process_input = match input.len() { + x if x > 1 => { + let tag = input[0].tag.clone(); + vec![Value { + value: UntaggedValue::Table(input), + tag, + }] + } + 1 => input, + _ => vec![], + }; + + to_process_input + .into_iter() + .map(move |value| match value_to_bson_value(&value) { + Ok(bson_value) => { + let value_span = value.tag.span; + + match bson_value_to_bytes(bson_value, name_tag.clone()) { + Ok(x) => ReturnSuccess::value(UntaggedValue::binary(x).into_value(name_span)), + _ => Err(ShellError::labeled_error_with_secondary( + "Expected a table with BSON-compatible structure from pipeline", + "requires BSON-compatible input", + name_span, + "originates from here".to_string(), + value_span, + )), + } + } + _ => Err(ShellError::labeled_error( + "Expected a table with BSON-compatible structure from pipeline", + "requires BSON-compatible input", + &name_tag, + )), + }) + .collect() +} diff --git a/crates/nu_plugin_to_sqlite/Cargo.toml b/crates/nu_plugin_to_sqlite/Cargo.toml new file mode 100644 index 0000000000..e765f27ee3 --- /dev/null +++ b/crates/nu_plugin_to_sqlite/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "A converter plugin to the SQLite format for Nushell" +edition = "2018" +license = "MIT" +name = "nu_plugin_to_sqlite" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +hex = "0.4.2" +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +nu-source = { path="../nu-source", version = "0.59.0" } +tempfile = "3.2.0" + +[dependencies.rusqlite] +features = ["bundled", "blob"] +version = "0.26.1" + +[build-dependencies] diff --git a/crates/nu_plugin_to_sqlite/src/lib.rs b/crates/nu_plugin_to_sqlite/src/lib.rs new file mode 100644 index 0000000000..3e814f55b7 --- /dev/null +++ b/crates/nu_plugin_to_sqlite/src/lib.rs @@ -0,0 +1,4 @@ +mod nu; +mod to_sqlite; + +pub use to_sqlite::ToSqlite; diff --git a/crates/nu_plugin_to_sqlite/src/main.rs b/crates/nu_plugin_to_sqlite/src/main.rs new file mode 100644 index 0000000000..5f69232256 --- /dev/null +++ b/crates/nu_plugin_to_sqlite/src/main.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_to_sqlite::ToSqlite; + +fn main() { + serve_plugin(&mut ToSqlite::new()) +} diff --git a/crates/nu_plugin_to_sqlite/src/nu/mod.rs b/crates/nu_plugin_to_sqlite/src/nu/mod.rs new file mode 100644 index 0000000000..08288db45a --- /dev/null +++ b/crates/nu_plugin_to_sqlite/src/nu/mod.rs @@ -0,0 +1,25 @@ +#[cfg(test)] +mod tests; + +use crate::ToSqlite; +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{ReturnValue, Signature, Value}; +use nu_source::Tag; + +impl Plugin for ToSqlite { + fn config(&mut self) -> Result { + Ok(Signature::build("to sqlite") + .desc("Convert table into sqlite binary") + .filter()) + } + + fn filter(&mut self, input: Value) -> Result, ShellError> { + self.state.push(input); + Ok(vec![]) + } + + fn end_filter(&mut self) -> Result, ShellError> { + crate::to_sqlite::to_sqlite(self.state.clone(), Tag::unknown()) + } +} diff --git a/crates/nu_plugin_to_sqlite/src/nu/tests.rs b/crates/nu_plugin_to_sqlite/src/nu/tests.rs new file mode 100644 index 0000000000..d14c19bee3 --- /dev/null +++ b/crates/nu_plugin_to_sqlite/src/nu/tests.rs @@ -0,0 +1 @@ +mod integration {} diff --git a/crates/nu_plugin_to_sqlite/src/to_sqlite.rs b/crates/nu_plugin_to_sqlite/src/to_sqlite.rs new file mode 100644 index 0000000000..69466338c9 --- /dev/null +++ b/crates/nu_plugin_to_sqlite/src/to_sqlite.rs @@ -0,0 +1,172 @@ +use hex::encode; +use nu_errors::ShellError; +use nu_protocol::{Dictionary, Primitive, ReturnSuccess, ReturnValue, UntaggedValue, Value}; +use nu_source::Tag; +use rusqlite::Connection; +use std::io::Read; + +#[derive(Default)] +pub struct ToSqlite { + pub state: Vec, +} + +impl ToSqlite { + pub fn new() -> ToSqlite { + ToSqlite { state: vec![] } + } +} +fn comma_concat(acc: String, current: String) -> String { + if acc.is_empty() { + current + } else { + format!("{}, {}", acc, current) + } +} + +fn get_columns(rows: &[Value]) -> Result { + match &rows[0].value { + UntaggedValue::Row(d) => Ok(d + .entries + .iter() + .map(|(k, _v)| k.clone()) + .fold("".to_string(), comma_concat)), + _ => Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Could not find table column names", + )), + } +} + +fn nu_value_to_sqlite_string(v: Value) -> String { + match &v.value { + UntaggedValue::Primitive(p) => match p { + Primitive::Nothing => "NULL".into(), + Primitive::BigInt(i) => i.to_string(), + Primitive::Int(i) => i.to_string(), + Primitive::Duration(i) => i.to_string(), + Primitive::Decimal(f) => f.to_string(), + Primitive::Filesize(u) => u.to_string(), + Primitive::GlobPattern(s) => format!("'{}'", s.replace("'", "''")), + Primitive::String(s) => format!("'{}'", s.replace("'", "''")), + Primitive::Boolean(true) => "1".into(), + Primitive::Boolean(_) => "0".into(), + Primitive::Date(d) => format!("'{}'", d), + Primitive::FilePath(p) => format!("'{}'", p.display().to_string().replace("'", "''")), + Primitive::Binary(u) => format!("x'{}'", encode(u)), + Primitive::BeginningOfStream + | Primitive::EndOfStream + | Primitive::ColumnPath(_) + | Primitive::Range(_) => "NULL".into(), + }, + _ => "NULL".into(), + } +} + +fn get_insert_values(rows: Vec) -> Result { + let values: Result, _> = rows + .into_iter() + .map(|value| match value.value { + UntaggedValue::Row(d) => Ok(format!( + "({})", + d.entries + .iter() + .map(|(_k, v)| nu_value_to_sqlite_string(v.clone())) + .fold("".to_string(), comma_concat) + )), + _ => Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Could not find table column names", + )), + }) + .collect(); + let values = values?; + Ok(values.join(", ")) +} + +fn generate_statements(table: Dictionary) -> Result<(String, String), std::io::Error> { + let table_name = match table.entries.get("table_name") { + Some(Value { + value: UntaggedValue::Primitive(Primitive::String(table_name)), + .. + }) => table_name, + _ => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Could not find table name", + )) + } + }; + let (columns, insert_values) = match table.entries.get("table_values") { + Some(Value { + value: UntaggedValue::Table(l), + .. + }) => { + if l.is_empty() { + return Ok((String::new(), String::new())); + } + (get_columns(l), get_insert_values(l.to_vec())) + } + _ => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Could not find table values", + )) + } + }; + + let create = format!("create table {}({})", table_name, columns?); + let insert = format!("insert into {} values {}", table_name, insert_values?); + Ok((create, insert)) +} + +fn sqlite_input_stream_to_bytes(values: Vec) -> Result { + // FIXME: should probably write a sqlite virtual filesystem + // that will allow us to use bytes as a file to avoid this + // write out, but this will require C code. Might be + // best done as a PR to rusqlite. + let mut tempfile = tempfile::NamedTempFile::new()?; + let conn = match Connection::open(tempfile.path()) { + Ok(conn) => conn, + Err(e) => return Err(std::io::Error::new(std::io::ErrorKind::Other, e)), + }; + let tag = values[0].tag.clone(); + for value in values { + match &value.value { + UntaggedValue::Row(d) => { + let (create, insert) = generate_statements(d.to_owned())?; + if create.is_empty() { + continue; + } + match conn + .execute(&create, []) + .and_then(|_| conn.execute(&insert, [])) + { + Ok(_) => (), + Err(e) => { + return Err(std::io::Error::new(std::io::ErrorKind::Other, e)); + } + } + } + other => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!("Expected row, found {:?}", other), + )) + } + } + } + let mut out = Vec::new(); + tempfile.read_to_end(&mut out)?; + Ok(UntaggedValue::binary(out).into_value(tag)) +} + +pub fn to_sqlite(input: Vec, name_tag: Tag) -> Result, ShellError> { + match sqlite_input_stream_to_bytes(input) { + Ok(out) => Ok(vec![ReturnSuccess::value(out)]), + _ => Err(ShellError::labeled_error( + "Expected a table with SQLite-compatible structure from pipeline", + "requires SQLite-compatible input", + name_tag, + )), + } +} diff --git a/crates/nu_plugin_tree/Cargo.toml b/crates/nu_plugin_tree/Cargo.toml new file mode 100644 index 0000000000..43af3be6bf --- /dev/null +++ b/crates/nu_plugin_tree/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "Tree viewer plugin for Nushell" +edition = "2018" +license = "MIT" +name = "nu_plugin_tree" +version = "0.59.0" + +[lib] +doctest = false + +[dependencies] +derive-new = "0.5.8" +nu-errors = { path="../nu-errors", version = "0.59.0" } +nu-plugin = { path="../nu-plugin", version = "0.59.0" } +nu-protocol = { path="../nu-protocol", version = "0.59.0" } +ptree = { version = "0.4.0", default-features = false } + + +[build-dependencies] diff --git a/crates/nu_plugin_tree/src/lib.rs b/crates/nu_plugin_tree/src/lib.rs new file mode 100644 index 0000000000..d71f024ce6 --- /dev/null +++ b/crates/nu_plugin_tree/src/lib.rs @@ -0,0 +1,4 @@ +mod nu; +mod tree; + +pub use tree::TreeViewer; diff --git a/crates/nu_plugin_tree/src/main.rs b/crates/nu_plugin_tree/src/main.rs new file mode 100644 index 0000000000..7ba6d9ea58 --- /dev/null +++ b/crates/nu_plugin_tree/src/main.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_tree::TreeViewer; + +fn main() { + serve_plugin(&mut TreeViewer); +} diff --git a/crates/nu_plugin_tree/src/nu/mod.rs b/crates/nu_plugin_tree/src/nu/mod.rs new file mode 100644 index 0000000000..fcec4e9bde --- /dev/null +++ b/crates/nu_plugin_tree/src/nu/mod.rs @@ -0,0 +1,19 @@ +use nu_errors::ShellError; +use nu_plugin::Plugin; +use nu_protocol::{CallInfo, Signature, Value}; + +use crate::tree::TreeView; +use crate::TreeViewer; + +impl Plugin for TreeViewer { + fn config(&mut self) -> Result { + Ok(Signature::build("tree").desc("View the contents of the pipeline as a tree.")) + } + + fn sink(&mut self, _call_info: CallInfo, input: Vec) { + for i in &input { + let view = TreeView::from_value(i); + let _ = view.render_view(); + } + } +} diff --git a/crates/nu_plugin_tree/src/tree.rs b/crates/nu_plugin_tree/src/tree.rs new file mode 100644 index 0000000000..7a84f8cad1 --- /dev/null +++ b/crates/nu_plugin_tree/src/tree.rs @@ -0,0 +1,80 @@ +use derive_new::new; +use nu_errors::ShellError; +use nu_protocol::{format_primitive, UntaggedValue, Value}; +use ptree::item::StringItem; +use ptree::output::print_tree_with; +use ptree::print_config::PrintConfig; +use ptree::style::{Color, Style}; +use ptree::TreeBuilder; + +pub struct TreeViewer; +#[derive(new)] +pub struct TreeView { + tree: StringItem, +} + +impl TreeView { + fn from_value_helper(value: &UntaggedValue, mut builder: &mut TreeBuilder) { + match value { + UntaggedValue::Primitive(p) => { + let _ = builder.add_empty_child(format_primitive(p, None)); + } + UntaggedValue::Row(o) => { + for (k, v) in &o.entries { + builder = builder.begin_child(k.clone()); + Self::from_value_helper(v, builder); + builder = builder.end_child(); + } + } + UntaggedValue::Table(l) => { + for elem in l { + Self::from_value_helper(elem, builder); + } + } + _ => {} + } + } + + pub fn from_value(value: &Value) -> TreeView { + let descs = value.data_descriptors(); + + let mut tree = TreeBuilder::new("".to_string()); + let mut builder = &mut tree; + + for desc in descs { + let value = match &value.value { + UntaggedValue::Row(d) => d.get_data(&desc).borrow().clone(), + _ => value.clone(), + }; + builder = builder.begin_child(desc.clone()); + Self::from_value_helper(&value, builder); + builder = builder.end_child(); + //entries.push((desc.name.clone(), value.borrow().copy())) + } + + TreeView::new(builder.build()) + } + + pub fn render_view(&self) -> Result<(), ShellError> { + // Set up the print configuration + let config = { + let mut config = PrintConfig::from_env(); + config.branch = Style { + foreground: Some(Color::Green), + dimmed: true, + ..Style::default() + }; + config.leaf = Style { + bold: true, + ..Style::default() + }; + config.indent = 4; + config + }; + + // Print out the tree using custom formatting + print_tree_with(&self.tree, &config)?; + + Ok(()) + } +} diff --git a/samples/wasm/Cargo.toml b/samples/wasm/Cargo.toml index 7f7d8ea963..95c8b4d175 100644 --- a/samples/wasm/Cargo.toml +++ b/samples/wasm/Cargo.toml @@ -2,7 +2,7 @@ authors = ["Nu authors"] edition = "2018" name = "wasm" -version = "0.1.0" +version = "0.59.0" [lib] crate-type = ["cdylib", "rlib"] diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000000..989a12fd2e --- /dev/null +++ b/src/README.md @@ -0,0 +1,5 @@ +# Nushell REPL + +This directory contains the main Nushell REPL (read eval print loop) as part of the CLI portion of Nushell, which creates the `nu` binary itself. + +Current versions of the `nu` binary will use the Nu argument parsing logic to parse the commandline arguments passed to `nu`, leaving the logic here to be a thin layer around what the core libraries. diff --git a/src/main.rs b/src/main.rs index d76e32c4a9..0a3cd51872 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,3 @@ -<<<<<<< HEAD -use nu_cli::App as CliApp; -use nu_errors::ShellError; - -fn main() -> Result<(), ShellError> { - let mut argv = vec![String::from("nu")]; - argv.extend(positionals()); - - CliApp::run(&argv) -} - -fn positionals() -> Vec { - std::env::args().skip(1).collect::>() -======= mod commands; mod config_files; mod eval_file; @@ -360,5 +346,4 @@ impl Command for Nu { }, ] } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/src/plugins/nu_plugin_core_inc.rs b/src/plugins/nu_plugin_core_inc.rs index 77b759b126..9421c713ce 100644 --- a/src/plugins/nu_plugin_core_inc.rs +++ b/src/plugins/nu_plugin_core_inc.rs @@ -1,14 +1,6 @@ -<<<<<<< HEAD -use nu_plugin::serve_plugin; -use nu_plugin_inc::Inc; - -fn main() { - serve_plugin(&mut Inc::new()); -======= use nu_plugin::{serve_plugin, CapnpSerializer}; use nu_plugin_inc::Inc; fn main() { serve_plugin(&mut Inc::new(), CapnpSerializer {}) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } diff --git a/tests/assets/nu_json/charset_result.hjson b/tests/assets/nu_json/charset_result.hjson new file mode 100644 index 0000000000..d1573b6162 --- /dev/null +++ b/tests/assets/nu_json/charset_result.hjson @@ -0,0 +1,5 @@ +{ + ql-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + js-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + ml-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +} \ No newline at end of file diff --git a/tests/assets/nu_json/charset_result.json b/tests/assets/nu_json/charset_result.json new file mode 100644 index 0000000000..6357d96db6 --- /dev/null +++ b/tests/assets/nu_json/charset_result.json @@ -0,0 +1,5 @@ +{ + "ql-ascii": "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", + "js-ascii": "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", + "ml-ascii": "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" +} \ No newline at end of file diff --git a/tests/assets/nu_json/charset_test.hjson b/tests/assets/nu_json/charset_test.hjson new file mode 100644 index 0000000000..7527b1e45b --- /dev/null +++ b/tests/assets/nu_json/charset_test.hjson @@ -0,0 +1,6 @@ +ql-ascii: ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +js-ascii: "! \"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" +ml-ascii: + ''' + ! "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + ''' diff --git a/tests/assets/nu_json/comments_result.hjson b/tests/assets/nu_json/comments_result.hjson new file mode 100644 index 0000000000..a99ce23dba --- /dev/null +++ b/tests/assets/nu_json/comments_result.hjson @@ -0,0 +1,26 @@ +{ + foo1: This is a string value. # part of the string + foo2: This is a string value. + bar1: This is a string value. // part of the string + bar2: This is a string value. + foobar1: This is a string value./* part of the string */ + foobar2: This is a string value. + rem1: "# test" + rem2: "// test" + rem3: "/* test */" + num1: 0 + num2: 0 + num3: 2 + true1: true + true2: true + true3: true + false1: false + false2: false + false3: false + null1: null + null2: null + null3: null + str1: 00 # part of the string + str2: 00.0 // part of the string + str3: 02 /* part of the string */ +} \ No newline at end of file diff --git a/tests/assets/nu_json/comments_result.json b/tests/assets/nu_json/comments_result.json new file mode 100644 index 0000000000..e247803e65 --- /dev/null +++ b/tests/assets/nu_json/comments_result.json @@ -0,0 +1,26 @@ +{ + "foo1": "This is a string value. # part of the string", + "foo2": "This is a string value.", + "bar1": "This is a string value. // part of the string", + "bar2": "This is a string value.", + "foobar1": "This is a string value./* part of the string */", + "foobar2": "This is a string value.", + "rem1": "# test", + "rem2": "// test", + "rem3": "/* test */", + "num1": 0, + "num2": 0, + "num3": 2, + "true1": true, + "true2": true, + "true3": true, + "false1": false, + "false2": false, + "false3": false, + "null1": null, + "null2": null, + "null3": null, + "str1": "00 # part of the string", + "str2": "00.0 // part of the string", + "str3": "02 /* part of the string */" +} \ No newline at end of file diff --git a/tests/assets/nu_json/comments_test.hjson b/tests/assets/nu_json/comments_test.hjson new file mode 100644 index 0000000000..7f1dfdcab6 --- /dev/null +++ b/tests/assets/nu_json/comments_test.hjson @@ -0,0 +1,48 @@ +// test +# all +// comment +/* +styles +*/ +# with lf + + + +# ! + +{ + # hjson style comment + foo1: This is a string value. # part of the string + foo2: "This is a string value." # a comment + + // js style comment + bar1: This is a string value. // part of the string + bar2: "This is a string value." // a comment + + /* js block style comments */foobar1:/* more */This is a string value./* part of the string */ + /* js block style comments */foobar2:/* more */"This is a string value."/* a comment */ + + rem1: "# test" + rem2: "// test" + rem3: "/* test */" + + num1: 0 # comment + num2: 0.0 // comment + num3: 2 /* comment */ + + true1: true # comment + true2: true // comment + true3: true /* comment */ + + false1: false # comment + false2: false // comment + false3: false /* comment */ + + null1: null # comment + null2: null // comment + null3: null /* comment */ + + str1: 00 # part of the string + str2: 00.0 // part of the string + str3: 02 /* part of the string */ +} diff --git a/tests/assets/nu_json/empty_result.hjson b/tests/assets/nu_json/empty_result.hjson new file mode 100644 index 0000000000..a75b45b28b --- /dev/null +++ b/tests/assets/nu_json/empty_result.hjson @@ -0,0 +1,3 @@ +{ + "": empty +} \ No newline at end of file diff --git a/tests/assets/nu_json/empty_result.json b/tests/assets/nu_json/empty_result.json new file mode 100644 index 0000000000..47f710fe23 --- /dev/null +++ b/tests/assets/nu_json/empty_result.json @@ -0,0 +1,3 @@ +{ + "": "empty" +} \ No newline at end of file diff --git a/tests/assets/nu_json/empty_test.hjson b/tests/assets/nu_json/empty_test.hjson new file mode 100644 index 0000000000..ac97a9d7ce --- /dev/null +++ b/tests/assets/nu_json/empty_test.hjson @@ -0,0 +1,3 @@ +{ + "": empty +} diff --git a/tests/assets/nu_json/failCharset1_test.hjson b/tests/assets/nu_json/failCharset1_test.hjson new file mode 100644 index 0000000000..da280393b2 --- /dev/null +++ b/tests/assets/nu_json/failCharset1_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid \u char + char: "\uxxxx" +} diff --git a/tests/assets/nu_json/failJSON02_test.json b/tests/assets/nu_json/failJSON02_test.json new file mode 100644 index 0000000000..6b7c11e5a5 --- /dev/null +++ b/tests/assets/nu_json/failJSON02_test.json @@ -0,0 +1 @@ +["Unclosed array" \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON05_test.json b/tests/assets/nu_json/failJSON05_test.json new file mode 100644 index 0000000000..ddf3ce3d24 --- /dev/null +++ b/tests/assets/nu_json/failJSON05_test.json @@ -0,0 +1 @@ +["double extra comma",,] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON06_test.json b/tests/assets/nu_json/failJSON06_test.json new file mode 100644 index 0000000000..ed91580e1b --- /dev/null +++ b/tests/assets/nu_json/failJSON06_test.json @@ -0,0 +1 @@ +[ , "<-- missing value"] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON07_test.json b/tests/assets/nu_json/failJSON07_test.json new file mode 100644 index 0000000000..8a96af3e4e --- /dev/null +++ b/tests/assets/nu_json/failJSON07_test.json @@ -0,0 +1 @@ +["Comma after the close"], \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON08_test.json b/tests/assets/nu_json/failJSON08_test.json new file mode 100644 index 0000000000..b28479c6ec --- /dev/null +++ b/tests/assets/nu_json/failJSON08_test.json @@ -0,0 +1 @@ +["Extra close"]] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON10_test.json b/tests/assets/nu_json/failJSON10_test.json new file mode 100644 index 0000000000..5d8c0047bd --- /dev/null +++ b/tests/assets/nu_json/failJSON10_test.json @@ -0,0 +1 @@ +{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON11_test.json b/tests/assets/nu_json/failJSON11_test.json new file mode 100644 index 0000000000..76eb95b458 --- /dev/null +++ b/tests/assets/nu_json/failJSON11_test.json @@ -0,0 +1 @@ +{"Illegal expression": 1 + 2} \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON12_test.json b/tests/assets/nu_json/failJSON12_test.json new file mode 100644 index 0000000000..77580a4522 --- /dev/null +++ b/tests/assets/nu_json/failJSON12_test.json @@ -0,0 +1 @@ +{"Illegal invocation": alert()} \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON13_test.json b/tests/assets/nu_json/failJSON13_test.json new file mode 100644 index 0000000000..379406b59b --- /dev/null +++ b/tests/assets/nu_json/failJSON13_test.json @@ -0,0 +1 @@ +{"Numbers cannot have leading zeroes": 013} \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON14_test.json b/tests/assets/nu_json/failJSON14_test.json new file mode 100644 index 0000000000..0ed366b38a --- /dev/null +++ b/tests/assets/nu_json/failJSON14_test.json @@ -0,0 +1 @@ +{"Numbers cannot be hex": 0x14} \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON15_test.json b/tests/assets/nu_json/failJSON15_test.json new file mode 100644 index 0000000000..fc8376b605 --- /dev/null +++ b/tests/assets/nu_json/failJSON15_test.json @@ -0,0 +1 @@ +["Illegal backslash escape: \x15"] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON16_test.json b/tests/assets/nu_json/failJSON16_test.json new file mode 100644 index 0000000000..3fe21d4b53 --- /dev/null +++ b/tests/assets/nu_json/failJSON16_test.json @@ -0,0 +1 @@ +[\naked] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON17_test.json b/tests/assets/nu_json/failJSON17_test.json new file mode 100644 index 0000000000..62b9214aed --- /dev/null +++ b/tests/assets/nu_json/failJSON17_test.json @@ -0,0 +1 @@ +["Illegal backslash escape: \017"] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON19_test.json b/tests/assets/nu_json/failJSON19_test.json new file mode 100644 index 0000000000..3b9c46fa9a --- /dev/null +++ b/tests/assets/nu_json/failJSON19_test.json @@ -0,0 +1 @@ +{"Missing colon" null} \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON20_test.json b/tests/assets/nu_json/failJSON20_test.json new file mode 100644 index 0000000000..27c1af3e72 --- /dev/null +++ b/tests/assets/nu_json/failJSON20_test.json @@ -0,0 +1 @@ +{"Double colon":: null} \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON21_test.json b/tests/assets/nu_json/failJSON21_test.json new file mode 100644 index 0000000000..62474573b2 --- /dev/null +++ b/tests/assets/nu_json/failJSON21_test.json @@ -0,0 +1 @@ +{"Comma instead of colon", null} \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON22_test.json b/tests/assets/nu_json/failJSON22_test.json new file mode 100644 index 0000000000..a7752581bc --- /dev/null +++ b/tests/assets/nu_json/failJSON22_test.json @@ -0,0 +1 @@ +["Colon instead of comma": false] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON23_test.json b/tests/assets/nu_json/failJSON23_test.json new file mode 100644 index 0000000000..494add1ca1 --- /dev/null +++ b/tests/assets/nu_json/failJSON23_test.json @@ -0,0 +1 @@ +["Bad value", truth] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON24_test.json b/tests/assets/nu_json/failJSON24_test.json new file mode 100644 index 0000000000..caff239bfc --- /dev/null +++ b/tests/assets/nu_json/failJSON24_test.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON26_test.json b/tests/assets/nu_json/failJSON26_test.json new file mode 100644 index 0000000000..845d26a6a5 --- /dev/null +++ b/tests/assets/nu_json/failJSON26_test.json @@ -0,0 +1 @@ +["tab\ character\ in\ string\ "] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON28_test.json b/tests/assets/nu_json/failJSON28_test.json new file mode 100644 index 0000000000..621a0101c6 --- /dev/null +++ b/tests/assets/nu_json/failJSON28_test.json @@ -0,0 +1,2 @@ +["line\ +break"] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON29_test.json b/tests/assets/nu_json/failJSON29_test.json new file mode 100644 index 0000000000..47ec421bb6 --- /dev/null +++ b/tests/assets/nu_json/failJSON29_test.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON30_test.json b/tests/assets/nu_json/failJSON30_test.json new file mode 100644 index 0000000000..8ab0bc4b8b --- /dev/null +++ b/tests/assets/nu_json/failJSON30_test.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON31_test.json b/tests/assets/nu_json/failJSON31_test.json new file mode 100644 index 0000000000..1cce602b51 --- /dev/null +++ b/tests/assets/nu_json/failJSON31_test.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON32_test.json b/tests/assets/nu_json/failJSON32_test.json new file mode 100644 index 0000000000..45cba7396f --- /dev/null +++ b/tests/assets/nu_json/failJSON32_test.json @@ -0,0 +1 @@ +{"Comma instead if closing brace": true, \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON33_test.json b/tests/assets/nu_json/failJSON33_test.json new file mode 100644 index 0000000000..ca5eb19dc9 --- /dev/null +++ b/tests/assets/nu_json/failJSON33_test.json @@ -0,0 +1 @@ +["mismatch"} \ No newline at end of file diff --git a/tests/assets/nu_json/failJSON34_test.json b/tests/assets/nu_json/failJSON34_test.json new file mode 100644 index 0000000000..921436427e --- /dev/null +++ b/tests/assets/nu_json/failJSON34_test.json @@ -0,0 +1,2 @@ +A quoteless string is OK, +but two must be contained in an array. diff --git a/tests/assets/nu_json/failKey1_test.hjson b/tests/assets/nu_json/failKey1_test.hjson new file mode 100644 index 0000000000..0026d2a1ae --- /dev/null +++ b/tests/assets/nu_json/failKey1_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid name + wrong name: 0 +} diff --git a/tests/assets/nu_json/failKey2_test.hjson b/tests/assets/nu_json/failKey2_test.hjson new file mode 100644 index 0000000000..4b5771a7d2 --- /dev/null +++ b/tests/assets/nu_json/failKey2_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid name + {name: 0 +} diff --git a/tests/assets/nu_json/failKey3_test.hjson b/tests/assets/nu_json/failKey3_test.hjson new file mode 100644 index 0000000000..3443a87f4b --- /dev/null +++ b/tests/assets/nu_json/failKey3_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid name + key,name: 0 +} diff --git a/tests/assets/nu_json/failKey4_test.hjson b/tests/assets/nu_json/failKey4_test.hjson new file mode 100644 index 0000000000..a7e9ce2aea --- /dev/null +++ b/tests/assets/nu_json/failKey4_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid name + : 0 +} diff --git a/tests/assets/nu_json/failMLStr1_test.hjson b/tests/assets/nu_json/failMLStr1_test.hjson new file mode 100644 index 0000000000..ca6410720b --- /dev/null +++ b/tests/assets/nu_json/failMLStr1_test.hjson @@ -0,0 +1,3 @@ +{ + # invalid multiline string + ml: ''' diff --git a/tests/assets/nu_json/failObj1_test.hjson b/tests/assets/nu_json/failObj1_test.hjson new file mode 100644 index 0000000000..ac7b761fbf --- /dev/null +++ b/tests/assets/nu_json/failObj1_test.hjson @@ -0,0 +1,6 @@ +{ + # invalid obj + noDelimiter + { + } +} diff --git a/tests/assets/nu_json/failObj2_test.hjson b/tests/assets/nu_json/failObj2_test.hjson new file mode 100644 index 0000000000..cdad47eefe --- /dev/null +++ b/tests/assets/nu_json/failObj2_test.hjson @@ -0,0 +1,6 @@ +{ + # invalid obj + noEnd + { + +} diff --git a/tests/assets/nu_json/failObj3_test.hjson b/tests/assets/nu_json/failObj3_test.hjson new file mode 100644 index 0000000000..f1176842de --- /dev/null +++ b/tests/assets/nu_json/failObj3_test.hjson @@ -0,0 +1,7 @@ +{ + # missing key + + [ + test + ] +} diff --git a/tests/assets/nu_json/failStr1a_test.hjson b/tests/assets/nu_json/failStr1a_test.hjson new file mode 100644 index 0000000000..91b930ca44 --- /dev/null +++ b/tests/assets/nu_json/failStr1a_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: ] +} diff --git a/tests/assets/nu_json/failStr1b_test.hjson b/tests/assets/nu_json/failStr1b_test.hjson new file mode 100644 index 0000000000..91da1a8dee --- /dev/null +++ b/tests/assets/nu_json/failStr1b_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: ]x +} diff --git a/tests/assets/nu_json/failStr1c_test.hjson b/tests/assets/nu_json/failStr1c_test.hjson new file mode 100644 index 0000000000..20a73079f2 --- /dev/null +++ b/tests/assets/nu_json/failStr1c_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + ] +] diff --git a/tests/assets/nu_json/failStr1d_test.hjson b/tests/assets/nu_json/failStr1d_test.hjson new file mode 100644 index 0000000000..555f88a915 --- /dev/null +++ b/tests/assets/nu_json/failStr1d_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + ]x +] diff --git a/tests/assets/nu_json/failStr2a_test.hjson b/tests/assets/nu_json/failStr2a_test.hjson new file mode 100644 index 0000000000..5a8b28feb7 --- /dev/null +++ b/tests/assets/nu_json/failStr2a_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: } +} diff --git a/tests/assets/nu_json/failStr2b_test.hjson b/tests/assets/nu_json/failStr2b_test.hjson new file mode 100644 index 0000000000..a7fc00de73 --- /dev/null +++ b/tests/assets/nu_json/failStr2b_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: }x +} diff --git a/tests/assets/nu_json/failStr2c_test.hjson b/tests/assets/nu_json/failStr2c_test.hjson new file mode 100644 index 0000000000..1fe46067b6 --- /dev/null +++ b/tests/assets/nu_json/failStr2c_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + } +] diff --git a/tests/assets/nu_json/failStr2d_test.hjson b/tests/assets/nu_json/failStr2d_test.hjson new file mode 100644 index 0000000000..ea8c99adcc --- /dev/null +++ b/tests/assets/nu_json/failStr2d_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + }x +] diff --git a/tests/assets/nu_json/failStr3a_test.hjson b/tests/assets/nu_json/failStr3a_test.hjson new file mode 100644 index 0000000000..ec5d0ad209 --- /dev/null +++ b/tests/assets/nu_json/failStr3a_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: { +} diff --git a/tests/assets/nu_json/failStr3b_test.hjson b/tests/assets/nu_json/failStr3b_test.hjson new file mode 100644 index 0000000000..2d0fff1fb9 --- /dev/null +++ b/tests/assets/nu_json/failStr3b_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: {x +} diff --git a/tests/assets/nu_json/failStr3c_test.hjson b/tests/assets/nu_json/failStr3c_test.hjson new file mode 100644 index 0000000000..2872a4d95f --- /dev/null +++ b/tests/assets/nu_json/failStr3c_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + { +] diff --git a/tests/assets/nu_json/failStr3d_test.hjson b/tests/assets/nu_json/failStr3d_test.hjson new file mode 100644 index 0000000000..949502ffc8 --- /dev/null +++ b/tests/assets/nu_json/failStr3d_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + {x +] diff --git a/tests/assets/nu_json/failStr4a_test.hjson b/tests/assets/nu_json/failStr4a_test.hjson new file mode 100644 index 0000000000..941f35bcd7 --- /dev/null +++ b/tests/assets/nu_json/failStr4a_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: [ +} diff --git a/tests/assets/nu_json/failStr4b_test.hjson b/tests/assets/nu_json/failStr4b_test.hjson new file mode 100644 index 0000000000..b7bb236281 --- /dev/null +++ b/tests/assets/nu_json/failStr4b_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: [x +} diff --git a/tests/assets/nu_json/failStr4c_test.hjson b/tests/assets/nu_json/failStr4c_test.hjson new file mode 100644 index 0000000000..ee927a4757 --- /dev/null +++ b/tests/assets/nu_json/failStr4c_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + [ +] diff --git a/tests/assets/nu_json/failStr4d_test.hjson b/tests/assets/nu_json/failStr4d_test.hjson new file mode 100644 index 0000000000..db50a529d8 --- /dev/null +++ b/tests/assets/nu_json/failStr4d_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + [x +] diff --git a/tests/assets/nu_json/failStr5a_test.hjson b/tests/assets/nu_json/failStr5a_test.hjson new file mode 100644 index 0000000000..4093f7a58d --- /dev/null +++ b/tests/assets/nu_json/failStr5a_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: : +} diff --git a/tests/assets/nu_json/failStr5b_test.hjson b/tests/assets/nu_json/failStr5b_test.hjson new file mode 100644 index 0000000000..eda96192ba --- /dev/null +++ b/tests/assets/nu_json/failStr5b_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: :x +} diff --git a/tests/assets/nu_json/failStr5c_test.hjson b/tests/assets/nu_json/failStr5c_test.hjson new file mode 100644 index 0000000000..63280735b4 --- /dev/null +++ b/tests/assets/nu_json/failStr5c_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + : +] diff --git a/tests/assets/nu_json/failStr5d_test.hjson b/tests/assets/nu_json/failStr5d_test.hjson new file mode 100644 index 0000000000..bfaef8e7da --- /dev/null +++ b/tests/assets/nu_json/failStr5d_test.hjson @@ -0,0 +1,5 @@ +[ + foo + # invalid quoteless string + :x +] diff --git a/tests/assets/nu_json/failStr6a_test.hjson b/tests/assets/nu_json/failStr6a_test.hjson new file mode 100644 index 0000000000..522333773d --- /dev/null +++ b/tests/assets/nu_json/failStr6a_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: , +} diff --git a/tests/assets/nu_json/failStr6b_test.hjson b/tests/assets/nu_json/failStr6b_test.hjson new file mode 100644 index 0000000000..90ad67bf5a --- /dev/null +++ b/tests/assets/nu_json/failStr6b_test.hjson @@ -0,0 +1,4 @@ +{ + # invalid quoteless string + ql: ,x +} diff --git a/tests/assets/nu_json/failStr6c_test.hjson b/tests/assets/nu_json/failStr6c_test.hjson new file mode 100644 index 0000000000..81d2af4c9c --- /dev/null +++ b/tests/assets/nu_json/failStr6c_test.hjson @@ -0,0 +1,6 @@ +[ + # invalid quoteless string + # note that if there were a preceding value the comma would + # be allowed/ignored as a separator/trailing comma + , +] diff --git a/tests/assets/nu_json/failStr6d_test.hjson b/tests/assets/nu_json/failStr6d_test.hjson new file mode 100644 index 0000000000..c1477293b9 --- /dev/null +++ b/tests/assets/nu_json/failStr6d_test.hjson @@ -0,0 +1,6 @@ +[ + # invalid quoteless string + # note that if there were a preceding value the comma would + # be allowed/ignored as a separator/trailing comma + ,x +] diff --git a/tests/assets/nu_json/kan_result.hjson b/tests/assets/nu_json/kan_result.hjson new file mode 100644 index 0000000000..d2b839add0 --- /dev/null +++ b/tests/assets/nu_json/kan_result.hjson @@ -0,0 +1,48 @@ +{ + numbers: + [ + 0 + 0 + 0 + 42 + 42.1 + -5 + -5.1 + 1701 + -1701 + 12.345 + -12.345 + ] + native: + [ + true + true + false + false + null + null + ] + strings: + [ + x 0 + .0 + 00 + 01 + 0 0 0 + 42 x + 42.1 asdf + 1.2.3 + -5 0 - + -5.1 -- + 17.01e2 + + -17.01e2 : + 12345e-3 @ + -12345e-3 $ + true true + x true + false false + x false + null null + x null + ] +} \ No newline at end of file diff --git a/tests/assets/nu_json/kan_result.json b/tests/assets/nu_json/kan_result.json new file mode 100644 index 0000000000..babb9d4e06 --- /dev/null +++ b/tests/assets/nu_json/kan_result.json @@ -0,0 +1,45 @@ +{ + "numbers": [ + 0, + 0, + 0, + 42, + 42.1, + -5, + -5.1, + 1701, + -1701, + 12.345, + -12.345 + ], + "native": [ + true, + true, + false, + false, + null, + null + ], + "strings": [ + "x 0", + ".0", + "00", + "01", + "0 0 0", + "42 x", + "42.1 asdf", + "1.2.3", + "-5 0 -", + "-5.1 --", + "17.01e2 +", + "-17.01e2 :", + "12345e-3 @", + "-12345e-3 $", + "true true", + "x true", + "false false", + "x false", + "null null", + "x null" + ] +} \ No newline at end of file diff --git a/tests/assets/nu_json/kan_test.hjson b/tests/assets/nu_json/kan_test.hjson new file mode 100644 index 0000000000..1e6906a96a --- /dev/null +++ b/tests/assets/nu_json/kan_test.hjson @@ -0,0 +1,49 @@ +{ + # the comma forces a whitespace check + numbers: + [ + 0 + 0 , + -0 + 42 , + 42.1 , + -5 + -5.1 + 17.01e2 + -17.01e2 + 12345e-3 , + -12345e-3 , + ] + native: + [ + true , + true + false , + false + null , + null + ] + strings: + [ + x 0 + .0 + 00 + 01 + 0 0 0 + 42 x + 42.1 asdf + 1.2.3 + -5 0 - + -5.1 -- + 17.01e2 + + -17.01e2 : + 12345e-3 @ + -12345e-3 $ + true true + x true + false false + x false + null null + x null + ] +} diff --git a/tests/assets/nu_json/keys_result.hjson b/tests/assets/nu_json/keys_result.hjson new file mode 100644 index 0000000000..876e6c3462 --- /dev/null +++ b/tests/assets/nu_json/keys_result.hjson @@ -0,0 +1,34 @@ +{ + unquoted_key: test + _unquoted: test + test-key: test + -test: test + .key: test + trailing: test + trailing2: test + "#c1": test + "foo#bar": test + "//bar": test + "foo//bar": test + "/*foo*/": test + "foo/*foo*/bar": test + "/*": test + "foo/*bar": test + "\"": test + "foo\"bar": test + "'''": test + "foo'''bar": test + ":": test + "foo:bar": test + "{": test + "foo{bar": test + "}": test + "foo}bar": test + "[": test + "foo[bar": test + "]": test + "foo]bar": test + nl1: test + nl2: test + nl3: test +} \ No newline at end of file diff --git a/tests/assets/nu_json/keys_result.json b/tests/assets/nu_json/keys_result.json new file mode 100644 index 0000000000..81fa480b21 --- /dev/null +++ b/tests/assets/nu_json/keys_result.json @@ -0,0 +1,34 @@ +{ + "unquoted_key": "test", + "_unquoted": "test", + "test-key": "test", + "-test": "test", + ".key": "test", + "trailing": "test", + "trailing2": "test", + "#c1": "test", + "foo#bar": "test", + "//bar": "test", + "foo//bar": "test", + "/*foo*/": "test", + "foo/*foo*/bar": "test", + "/*": "test", + "foo/*bar": "test", + "\"": "test", + "foo\"bar": "test", + "'''": "test", + "foo'''bar": "test", + ":": "test", + "foo:bar": "test", + "{": "test", + "foo{bar": "test", + "}": "test", + "foo}bar": "test", + "[": "test", + "foo[bar": "test", + "]": "test", + "foo]bar": "test", + "nl1": "test", + "nl2": "test", + "nl3": "test" +} \ No newline at end of file diff --git a/tests/assets/nu_json/keys_test.hjson b/tests/assets/nu_json/keys_test.hjson new file mode 100644 index 0000000000..38f5603814 --- /dev/null +++ b/tests/assets/nu_json/keys_test.hjson @@ -0,0 +1,48 @@ +{ + # unquoted keys + unquoted_key: test + _unquoted: test + test-key: test + -test: test + .key: test + # trailing spaces in key names are ignored + trailing : test + trailing2 : test + # comment char in key name + "#c1": test + "foo#bar": test + "//bar": test + "foo//bar": test + "/*foo*/": test + "foo/*foo*/bar": test + "/*": test + "foo/*bar": test + # quotes in key name + "\"": test + "foo\"bar": test + "'''": test + "foo'''bar": test + # control char in key name + ":": test + "foo:bar": test + "{": test + "foo{bar": test + "}": test + "foo}bar": test + "[": test + "foo[bar": test + "]": test + "foo]bar": test + # newline + nl1: + test + nl2 + : + test + + nl3 + + : + + test +} diff --git a/tests/assets/nu_json/oa_result.hjson b/tests/assets/nu_json/oa_result.hjson new file mode 100644 index 0000000000..db42ac9012 --- /dev/null +++ b/tests/assets/nu_json/oa_result.hjson @@ -0,0 +1,13 @@ +[ + a + {} + {} + [] + [] + { + b: 1 + c: [] + d: {} + } + [] +] \ No newline at end of file diff --git a/tests/assets/nu_json/oa_result.json b/tests/assets/nu_json/oa_result.json new file mode 100644 index 0000000000..f0955abeb5 --- /dev/null +++ b/tests/assets/nu_json/oa_result.json @@ -0,0 +1,13 @@ +[ + "a", + {}, + {}, + [], + [], + { + "b": 1, + "c": [], + "d": {} + }, + [] +] \ No newline at end of file diff --git a/tests/assets/nu_json/oa_test.hjson b/tests/assets/nu_json/oa_test.hjson new file mode 100644 index 0000000000..35bcdb4522 --- /dev/null +++ b/tests/assets/nu_json/oa_test.hjson @@ -0,0 +1,13 @@ +[ + a + {} + {} + [] + [] + { + b: 1 + c: [] + d: {} + } + [] +] diff --git a/tests/assets/nu_json/pass1_result.hjson b/tests/assets/nu_json/pass1_result.hjson new file mode 100644 index 0000000000..2a3f4c97f1 --- /dev/null +++ b/tests/assets/nu_json/pass1_result.hjson @@ -0,0 +1,78 @@ +[ + JSON Test Pattern pass1 + { + "object with 1 member": + [ + array with 1 element + ] + } + {} + [] + -42 + true + false + null + { + integer: 1234567890 + real: -9876.54321 + e: 1.23456789e-13 + E: 1.23456789e+34 + -: 2.3456789012e+76 + zero: 0 + one: 1 + space: " " + quote: '''"''' + backslash: \ + controls: "\b\f\n\r\t" + slash: / & / + alpha: abcdefghijklmnopqrstuvwyz + ALPHA: ABCDEFGHIJKLMNOPQRSTUVWYZ + digit: 0123456789 + 0123456789: digit + special: `1~!@#$%^&*()_+-={':[,]}|;.? + hex: Δ£δ•§θ¦«μ·―κ―ξ½Š + true: true + false: false + null: null + array: [] + object: {} + address: 50 St. James Street + url: http://www.JSON.org/ + comment: "// /* */": " " + " s p a c e d ": + [ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + ] + compact: + [ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + ] + jsontext: '''{"object with 1 member":["array with 1 element"]}''' + quotes: " " %22 0x22 034 " + "/\\\"μ«ΎλͺΎκ˜ο³žλ³šξ½Š\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?": A key can be any string + } + 0.5 + 98.6 + 99.44 + 1066 + 10 + 1 + 0.1 + 1 + 2 + 2 + rosebud +] \ No newline at end of file diff --git a/tests/assets/nu_json/pass1_result.json b/tests/assets/nu_json/pass1_result.json new file mode 100644 index 0000000000..69b354d05e --- /dev/null +++ b/tests/assets/nu_json/pass1_result.json @@ -0,0 +1,75 @@ +[ + "JSON Test Pattern pass1", + { + "object with 1 member": [ + "array with 1 element" + ] + }, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.54321, + "e": 1.23456789e-13, + "E": 1.23456789e+34, + "-": 2.3456789012e+76, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & /", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "Δ£δ•§θ¦«μ·―κ―ξ½Š", + "true": true, + "false": false, + "null": null, + "array": [], + "object": {}, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d ": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "compact": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \" %22 0x22 034 "", + "/\\\"μ«ΎλͺΎκ˜ο³žλ³šξ½Š\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?": "A key can be any string" + }, + 0.5, + 98.6, + 99.44, + 1066, + 10, + 1, + 0.1, + 1, + 2, + 2, + "rosebud" +] \ No newline at end of file diff --git a/tests/assets/nu_json/pass1_test.json b/tests/assets/nu_json/pass1_test.json new file mode 100644 index 0000000000..61cfd90c94 --- /dev/null +++ b/tests/assets/nu_json/pass1_test.json @@ -0,0 +1,58 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "-": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] \ No newline at end of file diff --git a/tests/assets/nu_json/pass2_result.hjson b/tests/assets/nu_json/pass2_result.hjson new file mode 100644 index 0000000000..5a9fd5e82b --- /dev/null +++ b/tests/assets/nu_json/pass2_result.hjson @@ -0,0 +1,39 @@ +[ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + Not too deep + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] +] \ No newline at end of file diff --git a/tests/assets/nu_json/pass2_result.json b/tests/assets/nu_json/pass2_result.json new file mode 100644 index 0000000000..2a71f5850e --- /dev/null +++ b/tests/assets/nu_json/pass2_result.json @@ -0,0 +1,39 @@ +[ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + [ + "Not too deep" + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] +] \ No newline at end of file diff --git a/tests/assets/nu_json/pass2_test.json b/tests/assets/nu_json/pass2_test.json new file mode 100644 index 0000000000..d3c63c7ad8 --- /dev/null +++ b/tests/assets/nu_json/pass2_test.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/tests/assets/nu_json/pass3_result.hjson b/tests/assets/nu_json/pass3_result.hjson new file mode 100644 index 0000000000..6db3fb61d7 --- /dev/null +++ b/tests/assets/nu_json/pass3_result.hjson @@ -0,0 +1,7 @@ +{ + "JSON Test Pattern pass3": + { + "The outermost value": must be an object or array. + "In this test": It is an object. + } +} \ No newline at end of file diff --git a/tests/assets/nu_json/pass3_result.json b/tests/assets/nu_json/pass3_result.json new file mode 100644 index 0000000000..d98cd2f881 --- /dev/null +++ b/tests/assets/nu_json/pass3_result.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} \ No newline at end of file diff --git a/tests/assets/nu_json/pass3_test.json b/tests/assets/nu_json/pass3_test.json new file mode 100644 index 0000000000..4528d51f1a --- /dev/null +++ b/tests/assets/nu_json/pass3_test.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} diff --git a/tests/assets/nu_json/pass4_result.hjson b/tests/assets/nu_json/pass4_result.hjson new file mode 100644 index 0000000000..9a037142aa --- /dev/null +++ b/tests/assets/nu_json/pass4_result.hjson @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/tests/assets/nu_json/pass4_result.json b/tests/assets/nu_json/pass4_result.json new file mode 100644 index 0000000000..9a037142aa --- /dev/null +++ b/tests/assets/nu_json/pass4_result.json @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/tests/assets/nu_json/pass4_test.json b/tests/assets/nu_json/pass4_test.json new file mode 100644 index 0000000000..069c2ae6b8 --- /dev/null +++ b/tests/assets/nu_json/pass4_test.json @@ -0,0 +1,2 @@ + +10 diff --git a/tests/assets/nu_json/passSingle_result.hjson b/tests/assets/nu_json/passSingle_result.hjson new file mode 100644 index 0000000000..e580fce159 --- /dev/null +++ b/tests/assets/nu_json/passSingle_result.hjson @@ -0,0 +1 @@ +allow quoteless strings \ No newline at end of file diff --git a/tests/assets/nu_json/passSingle_result.json b/tests/assets/nu_json/passSingle_result.json new file mode 100644 index 0000000000..1829d36f86 --- /dev/null +++ b/tests/assets/nu_json/passSingle_result.json @@ -0,0 +1 @@ +"allow quoteless strings" \ No newline at end of file diff --git a/tests/assets/nu_json/passSingle_test.hjson b/tests/assets/nu_json/passSingle_test.hjson new file mode 100644 index 0000000000..e580fce159 --- /dev/null +++ b/tests/assets/nu_json/passSingle_test.hjson @@ -0,0 +1 @@ +allow quoteless strings \ No newline at end of file diff --git a/tests/assets/nu_json/root_result.hjson b/tests/assets/nu_json/root_result.hjson new file mode 100644 index 0000000000..736372f62a --- /dev/null +++ b/tests/assets/nu_json/root_result.hjson @@ -0,0 +1,7 @@ +{ + database: + { + host: 127.0.0.1 + port: 555 + } +} \ No newline at end of file diff --git a/tests/assets/nu_json/root_result.json b/tests/assets/nu_json/root_result.json new file mode 100644 index 0000000000..21b01cd003 --- /dev/null +++ b/tests/assets/nu_json/root_result.json @@ -0,0 +1,6 @@ +{ + "database": { + "host": "127.0.0.1", + "port": 555 + } +} \ No newline at end of file diff --git a/tests/assets/nu_json/root_test.hjson b/tests/assets/nu_json/root_test.hjson new file mode 100644 index 0000000000..c0acd16eeb --- /dev/null +++ b/tests/assets/nu_json/root_test.hjson @@ -0,0 +1,6 @@ +// a object with the root braces omitted +database: +{ + host: 127.0.0.1 + port: 555 +} diff --git a/tests/assets/nu_json/stringify1_result.hjson b/tests/assets/nu_json/stringify1_result.hjson new file mode 100644 index 0000000000..77b2eddc13 --- /dev/null +++ b/tests/assets/nu_json/stringify1_result.hjson @@ -0,0 +1,49 @@ +{ + quotes: + { + num1: "1,2" + num2: "-1.1 ," + num3: "1e10 ,2" + num4: "-1e-10," + kw1: "true," + kw2: "false ," + kw3: "null,123" + close1: "1}" + close1b: "1 }" + close2: "1]" + close2b: "1 ]" + close3: "1," + close3b: "1 ," + comment1: "1#str" + comment2: "1//str" + comment3: "1/*str*/" + punc1: "{" + punc1b: "{foo" + punc2: "}" + punc2b: "}foo" + punc3: "[" + punc3b: "[foo" + punc4: "]" + punc4b: "]foo" + punc5: "," + punc5b: ",foo" + punc6: ":" + punc6b: ":foo" + } + noquotes: + { + num0: .1,2 + num1: 1.1.1,2 + num2: -.1, + num3: 1e10e,2 + num4: -1e--10, + kw1: true1, + kw2: false0, + kw3: null0, + close1: a} + close2: a] + comment1: a#str + comment2: a//str + comment3: a/*str*/ + } +} \ No newline at end of file diff --git a/tests/assets/nu_json/stringify1_result.json b/tests/assets/nu_json/stringify1_result.json new file mode 100644 index 0000000000..12514f8786 --- /dev/null +++ b/tests/assets/nu_json/stringify1_result.json @@ -0,0 +1,47 @@ +{ + "quotes": { + "num1": "1,2", + "num2": "-1.1 ,", + "num3": "1e10 ,2", + "num4": "-1e-10,", + "kw1": "true,", + "kw2": "false ,", + "kw3": "null,123", + "close1": "1}", + "close1b": "1 }", + "close2": "1]", + "close2b": "1 ]", + "close3": "1,", + "close3b": "1 ,", + "comment1": "1#str", + "comment2": "1//str", + "comment3": "1/*str*/", + "punc1": "{", + "punc1b": "{foo", + "punc2": "}", + "punc2b": "}foo", + "punc3": "[", + "punc3b": "[foo", + "punc4": "]", + "punc4b": "]foo", + "punc5": ",", + "punc5b": ",foo", + "punc6": ":", + "punc6b": ":foo" + }, + "noquotes": { + "num0": ".1,2", + "num1": "1.1.1,2", + "num2": "-.1,", + "num3": "1e10e,2", + "num4": "-1e--10,", + "kw1": "true1,", + "kw2": "false0,", + "kw3": "null0,", + "close1": "a}", + "close2": "a]", + "comment1": "a#str", + "comment2": "a//str", + "comment3": "a/*str*/" + } +} \ No newline at end of file diff --git a/tests/assets/nu_json/stringify1_test.hjson b/tests/assets/nu_json/stringify1_test.hjson new file mode 100644 index 0000000000..b353bf19cf --- /dev/null +++ b/tests/assets/nu_json/stringify1_test.hjson @@ -0,0 +1,50 @@ +// test if stringify produces correct output +{ + quotes: + { + num1: "1,2" + num2: "-1.1 ," + num3: "1e10 ,2" + num4: "-1e-10," + kw1: "true," + kw2: "false ," + kw3: "null,123" + close1: "1}" + close1b: "1 }" + close2: "1]" + close2b: "1 ]" + close3: "1," + close3b: "1 ," + comment1: "1#str" + comment2: "1//str" + comment3: "1/*str*/" + punc1: "{" + punc1b: "{foo" + punc2: "}" + punc2b: "}foo" + punc3: "[" + punc3b: "[foo" + punc4: "]" + punc4b: "]foo" + punc5: "," + punc5b: ",foo" + punc6: ":" + punc6b: ":foo" + } + noquotes: + { + num0: ".1,2" + num1: "1.1.1,2" + num2: "-.1," + num3: "1e10e,2" + num4: "-1e--10," + kw1: "true1," + kw2: "false0," + kw3: "null0," + close1: "a}" + close2: "a]" + comment1: "a#str" + comment2: "a//str" + comment3: "a/*str*/" + } +} diff --git a/tests/assets/nu_json/strings_result.hjson b/tests/assets/nu_json/strings_result.hjson new file mode 100644 index 0000000000..6ef06f8741 --- /dev/null +++ b/tests/assets/nu_json/strings_result.hjson @@ -0,0 +1,75 @@ +{ + text1: This is a valid string value. + text2: a \ is just a \ + text3: "You need quotes\tfor escapes" + text4a: " untrimmed " + text4b: " untrimmed" + text4c: "untrimmed " + multiline1: + ''' + first line + indented line + last line + ''' + multiline2: + ''' + first line + indented line + last line + ''' + multiline3: + ''' + first line + indented line + last line + + ''' + foo1a: asdf\"'a\s\w + foo1b: asdf\"'a\s\w + foo1c: asdf\"'a\s\w + foo2a: '''"asdf"''' + foo2b: '''"asdf"''' + foo3a: asdf''' + foo3b: "'''asdf" + foo4a: "asdf'''\nasdf" + foo4b: "asdf\n'''asdf" + arr: + [ + one + two + three + four + ] + not: + { + number: 5 + negative: -4.2 + yes: true + no: false + null: null + array: + [ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + -1 + 0.5 + ] + } + special: + { + true: "true" + false: "false" + null: "null" + one: "1" + two: "2" + minus: "-3" + } +} \ No newline at end of file diff --git a/tests/assets/nu_json/strings_result.json b/tests/assets/nu_json/strings_result.json new file mode 100644 index 0000000000..16321ba7a9 --- /dev/null +++ b/tests/assets/nu_json/strings_result.json @@ -0,0 +1,55 @@ +{ + "text1": "This is a valid string value.", + "text2": "a \\ is just a \\", + "text3": "You need quotes\tfor escapes", + "text4a": " untrimmed ", + "text4b": " untrimmed", + "text4c": "untrimmed ", + "multiline1": "first line\n indented line\nlast line", + "multiline2": "first line\n indented line\nlast line", + "multiline3": "first line\n indented line\nlast line\n", + "foo1a": "asdf\\\"'a\\s\\w", + "foo1b": "asdf\\\"'a\\s\\w", + "foo1c": "asdf\\\"'a\\s\\w", + "foo2a": "\"asdf\"", + "foo2b": "\"asdf\"", + "foo3a": "asdf'''", + "foo3b": "'''asdf", + "foo4a": "asdf'''\nasdf", + "foo4b": "asdf\n'''asdf", + "arr": [ + "one", + "two", + "three", + "four" + ], + "not": { + "number": 5, + "negative": -4.2, + "yes": true, + "no": false, + "null": null, + "array": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 0, + -1, + 0.5 + ] + }, + "special": { + "true": "true", + "false": "false", + "null": "null", + "one": "1", + "two": "2", + "minus": "-3" + } +} \ No newline at end of file diff --git a/tests/assets/nu_json/strings_test.hjson b/tests/assets/nu_json/strings_test.hjson new file mode 100644 index 0000000000..616895209f --- /dev/null +++ b/tests/assets/nu_json/strings_test.hjson @@ -0,0 +1,80 @@ +{ + # simple + + text1: This is a valid string value. + text2:a \ is just a \ + + text3: "You need quotes\tfor escapes" + + text4a: " untrimmed " + text4b: " untrimmed" + text4c: "untrimmed " + + # multiline string + + multiline1: + ''' + first line + indented line + last line + ''' + + multiline2: + '''first line + indented line + last line''' + + multiline3: + ''' + first line + indented line + last line + + ''' # trailing lf + + # escapes/no escape + + foo1a: asdf\"'a\s\w + foo1b: '''asdf\"'a\s\w''' + foo1c: "asdf\\\"'a\\s\\w" + + foo2a: "\"asdf\"" + foo2b: '''"asdf"''' + + foo3a: "asdf'''" + foo3b: "'''asdf" + + foo4a: "asdf'''\nasdf" + foo4b: "asdf\n'''asdf" + + # in arrays + arr: + [ + one + two + "three" + '''four''' + ] + + # not strings + not: + { + number: 5 + negative: -4.2 + yes: true + no: false + null: null + array: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -1, 0.5 ] + } + + # special quoted + special: + { + true: "true" + false: "false" + null: "null" + one: "1" + two: "2" + minus: "-3" + } +} diff --git a/tests/assets/nu_json/testlist.txt b/tests/assets/nu_json/testlist.txt new file mode 100644 index 0000000000..debb52c83e --- /dev/null +++ b/tests/assets/nu_json/testlist.txt @@ -0,0 +1,75 @@ +charset_test.hjson +comments_test.hjson +empty_test.hjson +failCharset1_test.hjson +failJSON02_test.json +failJSON05_test.json +failJSON06_test.json +failJSON07_test.json +failJSON08_test.json +failJSON10_test.json +failJSON11_test.json +failJSON12_test.json +failJSON13_test.json +failJSON14_test.json +failJSON15_test.json +failJSON16_test.json +failJSON17_test.json +failJSON19_test.json +failJSON20_test.json +failJSON21_test.json +failJSON22_test.json +failJSON23_test.json +failJSON24_test.json +failJSON26_test.json +failJSON28_test.json +failJSON29_test.json +failJSON30_test.json +failJSON31_test.json +failJSON32_test.json +failJSON33_test.json +failJSON34_test.json +failKey1_test.hjson +failKey2_test.hjson +failKey3_test.hjson +failKey4_test.hjson +failMLStr1_test.hjson +failObj1_test.hjson +failObj2_test.hjson +failObj3_test.hjson +failStr1a_test.hjson +failStr1b_test.hjson +failStr1c_test.hjson +failStr1d_test.hjson +failStr2a_test.hjson +failStr2b_test.hjson +failStr2c_test.hjson +failStr2d_test.hjson +failStr3a_test.hjson +failStr3b_test.hjson +failStr3c_test.hjson +failStr3d_test.hjson +failStr4a_test.hjson +failStr4b_test.hjson +failStr4c_test.hjson +failStr4d_test.hjson +failStr5a_test.hjson +failStr5b_test.hjson +failStr5c_test.hjson +failStr5d_test.hjson +failStr6a_test.hjson +failStr6b_test.hjson +failStr6c_test.hjson +failStr6d_test.hjson +kan_test.hjson +keys_test.hjson +oa_test.hjson +pass1_test.json +pass2_test.json +pass3_test.json +pass4_test.json +passSingle_test.hjson +root_test.hjson +stringify1_test.hjson +strings_test.hjson +trail_test.hjson \ No newline at end of file diff --git a/tests/assets/nu_json/trail_result.hjson b/tests/assets/nu_json/trail_result.hjson new file mode 100644 index 0000000000..57ffc716bd --- /dev/null +++ b/tests/assets/nu_json/trail_result.hjson @@ -0,0 +1,3 @@ +{ + foo: 0 -- this string starts at 0 and ends at 1, preceding and trailing whitespace is ignored -- 1 +} \ No newline at end of file diff --git a/tests/assets/nu_json/trail_result.json b/tests/assets/nu_json/trail_result.json new file mode 100644 index 0000000000..451c8ceb94 --- /dev/null +++ b/tests/assets/nu_json/trail_result.json @@ -0,0 +1,3 @@ +{ + "foo": "0 -- this string starts at 0 and ends at 1, preceding and trailing whitespace is ignored -- 1" +} \ No newline at end of file diff --git a/tests/assets/nu_json/trail_test.hjson b/tests/assets/nu_json/trail_test.hjson new file mode 100644 index 0000000000..62d98e98a3 --- /dev/null +++ b/tests/assets/nu_json/trail_test.hjson @@ -0,0 +1,2 @@ +// the following line contains trailing whitespace: +foo: 0 -- this string starts at 0 and ends at 1, preceding and trailing whitespace is ignored -- 1 diff --git a/tests/fixtures/formats/appveyor.yml b/tests/fixtures/formats/appveyor.yml new file mode 100644 index 0000000000..770f32a2a9 --- /dev/null +++ b/tests/fixtures/formats/appveyor.yml @@ -0,0 +1,31 @@ +image: Visual Studio 2017 + +environment: + global: + PROJECT_NAME: nushell + RUST_BACKTRACE: 1 + matrix: + - TARGET: x86_64-pc-windows-msvc + CHANNEL: nightly + BITS: 64 + +install: + - set PATH=C:\msys64\mingw%BITS%\bin;C:\msys64\usr\bin;%PATH% + - curl -sSf -o rustup-init.exe https://win.rustup.rs + # Install rust + - rustup-init.exe -y --default-host %TARGET% --default-toolchain %CHANNEL%-%TARGET% + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + # Required for Racer autoconfiguration + - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" + + +build: false + +test_script: + # compile #[cfg(not(test))] code + - cargo build --verbose + - cargo test --all --verbose + +cache: + - target -> Cargo.lock + - C:\Users\appveyor\.cargo\registry -> Cargo.lock diff --git a/tests/fixtures/formats/caco3_plastics.csv b/tests/fixtures/formats/caco3_plastics.csv new file mode 100644 index 0000000000..8b04b00c0e --- /dev/null +++ b/tests/fixtures/formats/caco3_plastics.csv @@ -0,0 +1,10 @@ +importer,shipper,tariff_item,name,origin,shipped_at,arrived_at,net_weight,fob_price,cif_price,cif_per_net_weight +PLASTICOS RIVAL CIA LTDA,S A REVERTE,2509000000,CARBONATO DE CALCIO TIPO CALCIPORE 160 T AL,SPAIN,18/03/2016,17/04/2016,"81,000.00","14,417.58","18,252.34",0.23 +MEXICHEM ECUADOR S.A.,OMYA ANDINA S A,2836500000,CARBONATO,COLOMBIA,07/07/2016,10/07/2016,"26,000.00","7,072.00","8,127.18",0.31 +PLASTIAZUAY SA,SA REVERTE,2836500000,CARBONATO DE CALCIO,SPAIN,27/07/2016,09/08/2016,"81,000.00","8,100.00","11,474.55",0.14 +PLASTICOS RIVAL CIA LTDA,AND ENDUSTRIYEL HAMMADDELER DIS TCARET LTD.STI.,2836500000,CALCIUM CARBONATE ANADOLU ANDCARB CT-1,TURKEY,04/10/2016,11/11/2016,"100,000.00","17,500.00","22,533.75",0.23 +QUIMICA COMERCIAL QUIMICIAL CIA. LTDA.,SA REVERTE,2836500000,CARBONATO DE CALCIO,SPAIN,24/06/2016,12/07/2016,"27,000.00","3,258.90","5,585.00",0.21 +PICA PLASTICOS INDUSTRIALES C.A.,OMYA ANDINA S.A,3824909999,CARBONATO DE CALCIO,COLOMBIA,01/01/1900,18/01/2016,"66,500.00","12,635.00","18,670.52",0.28 +PLASTIQUIM S.A.,OMYA ANDINA S.A NIT 830.027.386-6,3824909999,CARBONATO DE CALCIO RECUBIERTO CON ACIDO ESTEARICO OMYA CARB 1T CG BBS 1000,COLOMBIA,01/01/1900,25/10/2016,"33,000.00","6,270.00","9,999.00",0.30 +QUIMICOS ANDINOS QUIMANDI S.A.,SIBELCO COLOMBIA SAS,3824909999,CARBONATO DE CALCIO RECUBIERTO,COLOMBIA,01/11/2016,03/11/2016,"52,000.00","8,944.00","13,039.05",0.25 +TIGRE ECUADOR S.A. ECUATIGRE,OMYA ANDINA S.A NIT 830.027.386-6,3824909999,CARBONATO DE CALCIO RECUBIERTO CON ACIDO ESTEARICO OMYACARB 1T CG BPA 25 NO,COLOMBIA,01/01/1900,28/10/2016,"66,000.00","11,748.00","18,216.00",0.28 diff --git a/tests/fixtures/formats/caco3_plastics.tsv b/tests/fixtures/formats/caco3_plastics.tsv new file mode 100644 index 0000000000..071baaae30 --- /dev/null +++ b/tests/fixtures/formats/caco3_plastics.tsv @@ -0,0 +1,10 @@ +importer shipper tariff_item name origin shipped_at arrived_at net_weight fob_price cif_price cif_per_net_weight +PLASTICOS RIVAL CIA LTDA S A REVERTE 2509000000 CARBONATO DE CALCIO TIPO CALCIPORE 160 T AL SPAIN 18/03/2016 17/04/2016 81,000.00 14,417.58 18,252.34 0.23 +MEXICHEM ECUADOR S.A. OMYA ANDINA S A 2836500000 CARBONATO COLOMBIA 07/07/2016 10/07/2016 26,000.00 7,072.00 8,127.18 0.31 +PLASTIAZUAY SA SA REVERTE 2836500000 CARBONATO DE CALCIO SPAIN 27/07/2016 09/08/2016 81,000.00 8,100.00 11,474.55 0.14 +PLASTICOS RIVAL CIA LTDA AND ENDUSTRIYEL HAMMADDELER DIS TCARET LTD.STI. 2836500000 CALCIUM CARBONATE ANADOLU ANDCARB CT-1 TURKEY 04/10/2016 11/11/2016 100,000.00 17,500.00 22,533.75 0.23 +QUIMICA COMERCIAL QUIMICIAL CIA. LTDA. SA REVERTE 2836500000 CARBONATO DE CALCIO SPAIN 24/06/2016 12/07/2016 27,000.00 3,258.90 5,585.00 0.21 +PICA PLASTICOS INDUSTRIALES C.A. OMYA ANDINA S.A 3824909999 CARBONATO DE CALCIO COLOMBIA 01/01/1900 18/01/2016 66,500.00 12,635.00 18,670.52 0.28 +PLASTIQUIM S.A. OMYA ANDINA S.A NIT 830.027.386-6 3824909999 CARBONATO DE CALCIO RECUBIERTO CON ACIDO ESTEARICO OMYA CARB 1T CG BBS 1000 COLOMBIA 01/01/1900 25/10/2016 33,000.00 6,270.00 9,999.00 0.30 +QUIMICOS ANDINOS QUIMANDI S.A. SIBELCO COLOMBIA SAS 3824909999 CARBONATO DE CALCIO RECUBIERTO COLOMBIA 01/11/2016 03/11/2016 52,000.00 8,944.00 13,039.05 0.25 +TIGRE ECUADOR S.A. ECUATIGRE OMYA ANDINA S.A NIT 830.027.386-6 3824909999 CARBONATO DE CALCIO RECUBIERTO CON ACIDO ESTEARICO OMYACARB 1T CG BPA 25 NO COLOMBIA 01/01/1900 28/10/2016 66,000.00 11,748.00 18,216.00 0.28 diff --git a/tests/fixtures/formats/cargo_sample.toml b/tests/fixtures/formats/cargo_sample.toml new file mode 100644 index 0000000000..c36a40e0ad --- /dev/null +++ b/tests/fixtures/formats/cargo_sample.toml @@ -0,0 +1,55 @@ +[package] +name = "nu" +version = "0.1.1" +authors = ["The Nu Project Contributors"] +description = "a new type of shell" +license = "ISC" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rustyline = "4.1.0" +sysinfo = "0.8.4" +chrono = { version = "0.4.6", features = ["serde"] } +chrono-tz = "0.5.1" +derive-new = "0.5.6" +prettytable-rs = "0.8.0" +itertools = "0.8.0" +ansi_term = "0.11.0" +conch-parser = "0.1.1" +nom = "5.0.0-beta1" +dunce = "1.0.0" +indexmap = { version = "1.0.2", features = ["serde-1"] } +chrono-humanize = "0.0.11" +byte-unit = "2.1.0" +ordered-float = "1.0.2" +prettyprint = "0.6.0" +cursive = { version = "0.12.0", features = ["pancurses-backend"], default-features = false } +futures-preview = { version = "0.3.0-alpha.16", features = ["compat", "io-compat"] } +futures-sink-preview = "0.3.0-alpha.16" +tokio-fs = "0.1.6" +futures_codec = "0.2.2" +term = "0.5.2" +bytes = "0.4.12" +log = "0.4.6" +pretty_env_logger = "0.3.0" +lalrpop-util = "0.17.0" +regex = "1.1.6" +serde = "1.0.91" +serde_json = "1.0.39" +serde_derive = "1.0.91" +getset = "0.0.7" +logos = "0.10.0-rc2" +logos-derive = "0.10.0-rc2" +language-reporting = "0.3.0" +directories = "2.0.2" +toml = "0.5.1" +toml-query = "0.9.0" + +[dependencies.pancurses] +version = "0.16" +features = ["win32a"] + +[dev-dependencies] +pretty_assertions = "0.6.1" diff --git a/tests/fixtures/formats/jonathan.xml b/tests/fixtures/formats/jonathan.xml new file mode 100644 index 0000000000..0ce0016c19 --- /dev/null +++ b/tests/fixtures/formats/jonathan.xml @@ -0,0 +1,22 @@ + + + + Jonathan Turner + http://www.jonathanturner.org + + + + Creating crossplatform Rust terminal apps + <p><img src="/images/pikachu.jpg" alt="Pikachu animation in Windows" /></p> + +<p><em>Look Mom, Pikachu running in Windows CMD!</em></p> + +<p>Part of the adventure is not seeing the way ahead and going anyway.</p> + + Mon, 05 Oct 2015 00:00:00 +0000 + http://www.jonathanturner.org/2015/10/off-to-new-adventures.html + http://www.jonathanturner.org/2015/10/off-to-new-adventures.html + + + + diff --git a/tests/fixtures/formats/lines_test.txt b/tests/fixtures/formats/lines_test.txt new file mode 100644 index 0000000000..034e56b61e --- /dev/null +++ b/tests/fixtures/formats/lines_test.txt @@ -0,0 +1,2 @@ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +yyy diff --git a/tests/fixtures/formats/random_numbers.csv b/tests/fixtures/formats/random_numbers.csv new file mode 100644 index 0000000000..5e5c694657 --- /dev/null +++ b/tests/fixtures/formats/random_numbers.csv @@ -0,0 +1,51 @@ +random numbers +5 +2 +0 +5 +1 +3 +5 +2 +1 +1 +0 +5 +1 +0 +0 +4 +0 +4 +5 +2 +2 +4 +3 +2 +5 +3 +1 +0 +5 +1 +2 +2 +5 +0 +1 +1 +5 +1 +1 +3 +3 +1 +5 +0 +2 +1 +3 +1 +1 +2 diff --git a/tests/fixtures/formats/sample-ls-output.json b/tests/fixtures/formats/sample-ls-output.json new file mode 100644 index 0000000000..4636f0353d --- /dev/null +++ b/tests/fixtures/formats/sample-ls-output.json @@ -0,0 +1 @@ +[{"name":"a.txt","type":"File","size":3444,"modified":"2020-07-1918:26:30.560716967UTC"},{"name":"B.txt","type":"File","size":1341,"modified":"2020-07-1918:26:30.561021953UTC"},{"name":"C","type":"Dir","size":118253,"modified":"2020-07-1918:26:30.562092480UTC"}] diff --git a/tests/fixtures/formats/sample-ps-output.json b/tests/fixtures/formats/sample-ps-output.json new file mode 100644 index 0000000000..7ae34d66e9 --- /dev/null +++ b/tests/fixtures/formats/sample-ps-output.json @@ -0,0 +1 @@ +[{"pid":10390,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":132112384,"virtual":4989624320},{"pid":10461,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":126992384,"virtual":4995346432},{"pid":10530,"name":"kworker/6:1-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":10593,"name":"kworker/1:1-mm_percpu_wq","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":10650,"name":"chrome","status":"Sleeping","cpu":8.026974,"mem":262434816,"virtual":5217419264},{"pid":10803,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":48173056,"virtual":542531584},{"pid":11191,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":124092416,"virtual":4975763456},{"pid":11210,"name":"kworker/7:0-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":11254,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":113070080,"virtual":4971659264},{"pid":11279,"name":"kworker/u16:0-events_unbound","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":11476,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":88993792,"virtual":4937097216},{"pid":12755,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":163397632,"virtual":5034328064},{"pid":12772,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":113561600,"virtual":4985073664},{"pid":14351,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":111861760,"virtual":4962754560},{"pid":17818,"name":"udisksd","status":"Sleeping","cpu":0.0,"mem":14409728,"virtual":402935808},{"pid":17815,"name":".gvfs-udisks2-v","status":"Sleeping","cpu":0.0,"mem":16199680,"virtual":585306112},{"pid":17831,"name":".gvfs-mtp-volum","status":"Sleeping","cpu":0.0,"mem":6393856,"virtual":454680576},{"pid":17836,"name":".gvfs-gphoto2-v","status":"Sleeping","cpu":0.0,"mem":7110656,"virtual":456966144},{"pid":17841,"name":".gvfs-afc-volum","status":"Sleeping","cpu":0.0,"mem":8585216,"virtual":537448448},{"pid":17846,"name":".gvfsd-trash-wr","status":"Sleeping","cpu":0.0,"mem":12767232,"virtual":577998848},{"pid":17856,"name":".gvfsd-network-","status":"Sleeping","cpu":0.0,"mem":13295616,"virtual":654110720},{"pid":17862,"name":".gvfsd-dnssd-wr","status":"Sleeping","cpu":0.0,"mem":7639040,"virtual":533233664},{"pid":17869,"name":"dconf-service","status":"Sleeping","cpu":0.0,"mem":5365760,"virtual":158957568},{"pid":18153,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":183738368,"virtual":5128962048},{"pid":23033,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":166035456,"virtual":5074878464},{"pid":24101,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":101224448,"virtual":4956262400},{"pid":24832,"name":"kworker/7:2-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":24912,"name":"kworker/5:2-events_power_efficient","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":25228,"name":"kworker/4:3-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":25678,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":117522432,"virtual":4970983424},{"pid":25706,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":30760960,"virtual":528375808},{"pid":26080,"name":"kworker/1:0-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":26818,"name":"kworker/2:0-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":26827,"name":"kworker/6:2-mm_percpu_wq","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":26832,"name":"kworker/0:2-mm_percpu_wq","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":26843,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":116621312,"virtual":4982403072},{"pid":27163,"name":"kworker/3:2-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":27800,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":128200704,"virtual":4965363712},{"pid":27820,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":54960128,"virtual":4895596544},{"pid":27898,"name":"kworker/3:0-mm_percpu_wq","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":27977,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":141930496,"virtual":4982546432},{"pid":28035,"name":"kworker/u16:1-events_unbound","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":28104,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":126853120,"virtual":5003902976},{"pid":28158,"name":"nu","status":"Sleeping","cpu":0.0,"mem":27344896,"virtual":870764544},{"pid":28236,"name":"chrome","status":"Sleeping","cpu":0.0,"mem":450560000,"virtual":5389582336},{"pid":29186,"name":"kworker/5:0-events","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":30140,"name":"kworker/u16:2-events_unbound","status":"Idle","cpu":0.0,"mem":0,"virtual":0},{"pid":30142,"name":"nu_plugin_core_","status":"Zombie","cpu":0.0,"mem":0,"virtual":0},{"pid":30356,"name":"sh","status":"Sleeping","cpu":0.0,"mem":3743744,"virtual":224092160},{"pid":30360,"name":"nu_plugin_core_ps","status":"Sleeping","cpu":80.23046000000001,"mem":6422528,"virtual":633016320}] \ No newline at end of file diff --git a/tests/fixtures/formats/sample-simple.json b/tests/fixtures/formats/sample-simple.json new file mode 100644 index 0000000000..7986b6e546 --- /dev/null +++ b/tests/fixtures/formats/sample-simple.json @@ -0,0 +1,4 @@ +{ + "first": "first", + "second": "this\nshould\nbe\nseparate\nlines" +} \ No newline at end of file diff --git a/tests/fixtures/formats/sample-sys-output.json b/tests/fixtures/formats/sample-sys-output.json new file mode 100644 index 0000000000..122fd85941 --- /dev/null +++ b/tests/fixtures/formats/sample-sys-output.json @@ -0,0 +1,125 @@ +{ + "host": { + "name": "Linux", + "release": "5.4.33", + "version": "#1-NixOS SMP Fri Apr 17 08:50:26 UTC 2020", + "hostname": "nixos", + "arch": "x86_64", + "uptime": 105126, + "sessions": [ + "alexj" + ] + }, + "cpu": { + "cores": 8, + "current ghz": 2.4200000000000004, + "min ghz": 0.39999999999999997, + "max ghz": 3.4000000000000004 + }, + "disks": [ + { + "device": "/dev/disk/by-uuid/e9adff48-c37b-4631-b98b-eaec9b410ba3", + "type": "ext4", + "mount": "/", + "total": 483445473280, + "used": 121866776576, + "free": 336949624832 + }, + { + "device": "/dev/disk/by-uuid/e9adff48-c37b-4631-b98b-eaec9b410ba3", + "type": "ext4", + "mount": "/nix/store", + "total": 483445473280, + "used": 121866776576, + "free": 336949624832 + }, + { + "device": "/dev/sda3", + "type": "vfat", + "mount": "/boot", + "total": 534757376, + "used": 72650752, + "free": 462106624 + } + ], + "mem": { + "total": 16256524000, + "free": 3082268000, + "swap total": 18874344000, + "swap free": 18874344000 + }, + "temp": [ + { + "unit": "iwlwifi_1", + "temp": 42.0 + }, + { + "unit": "acpitz", + "temp": 53.00000000000001, + "critical": 103.0 + }, + { + "unit": "coretemp", + "label": "Core 1", + "temp": 52.00000000000001, + "high": 100.0, + "critical": 100.0 + }, + { + "unit": "coretemp", + "label": "Core 2", + "temp": 52.00000000000001, + "high": 100.0, + "critical": 100.0 + }, + { + "unit": "coretemp", + "label": "Package id 0", + "temp": 52.00000000000001, + "high": 100.0, + "critical": 100.0 + }, + { + "unit": "coretemp", + "label": "Core 3", + "temp": 51.00000000000001, + "high": 100.0, + "critical": 100.0 + }, + { + "unit": "coretemp", + "label": "Core 0", + "temp": 51.00000000000001, + "high": 100.0, + "critical": 100.0 + }, + { + "unit": "pch_skylake", + "temp": 48.00000000000001 + } + ], + "net": [ + { + "name": "wlp2s0", + "sent": 387642399, + "recv": 15324719784 + }, + { + "name": "lo", + "sent": 2667, + "recv": 2667 + }, + { + "name": "vboxnet0", + "sent": 0, + "recv": 0 + } + ], + "battery": [ + { + "vendor": "ASUSTeK", + "model": "ASUS Battery", + "cycles": 445 + } + ] +} diff --git a/tests/fixtures/formats/sample.bson b/tests/fixtures/formats/sample.bson new file mode 100644 index 0000000000000000000000000000000000000000..ff51ae2072e1415afe592cfac9fc464acc920a20 GIT binary patch literal 561 zcmXqHVqjp8&rD&6&05L7&dlbK;e_8NEJgYGB@CiKDP{wPOa_>W#8k-%V$}@pM#9?| z6M>>2@WGxbiGdBs$Vkn}$!B0mX0QNqfZ9ZW6jOF;C0Me!q%~;mixsG(9B3H>Q!IluJS*N{> zF*tdvUX42u;xdKu{Gyx`kY|{U8N3iG&)qLJtf&=u!)VK##9#;%XG+dbNo4@JE+@4_ zp+dn{q0*Xxxi~q$AeBJ?D9Ts~BtSsG0Z1^LFem~ksGBb^<-~5UQ9bX&A(+g-2oz_! zkQmFrY>J}B5~_w1s>Twm#*D!YZcdV!_sqD`q2- z&_g}QY|dbUWKb5=AR*2~h7~W1j^qGc1=S{iqRoOq6{w97loBA|gS~Jf!@>VT&lHa1Z!Q|-k)cVTi%b|*2h^Ap$$ zegHd58*BXl;ui>_kV*(xB%m{UnrLIG82%4CFVE~V&957FXX*VyW)d~Xi%+pp9oAr+ zvl*orV`Q6W+igfYxtsIb7Y~fY-oD%mY=NW|MhCQI2LuEl009U<00Izz00bZa0SG|g zKN9FjKboB6b0+TVWT5ldl%w98TkLh0duq8myUWi+v#7kV`euUHt={-w;Oo=ww4 z>pXN3$h#>I#NU*MA+K{8HL7C9-TA*pXN>;PC0)=@J4HYM0uX=z1Rwwb2tWV=5P$## zAn-f|L`^Wy6QZ%>Ng?>I>)r@1#@+efqiy&7|D1l<2?7ETfB*y_009U<00Izz00bZa zfkzaW_vB{Nq* +Subject: Test Message +From: "from@example.com" +Reply-To: "replyto@example.com" +To: to@example.com +Content-Type: multipart/alternative; boundary="0000000000009d71fb05adf6528a" + +--0000000000009d71fb05adf6528a +Content-Type: text/plain; charset="UTF-8" + +Test Message + +--0000000000009d71fb05adf6528a +Content-Type: text/html; charset="UTF-8" + +

Test Message
+ +--0000000000009d71fb05adf6528a-- diff --git a/tests/fixtures/formats/sample.ini b/tests/fixtures/formats/sample.ini new file mode 100644 index 0000000000..c8f2485287 --- /dev/null +++ b/tests/fixtures/formats/sample.ini @@ -0,0 +1,19 @@ +[SectionOne] + +key = value +integer = 1234 +real = 3.14 +string1 = 'Case 1' +string2 = "Case 2" + +[SectionTwo] + +; comment line +key = new value +integer = 5678 +real = 3.14 +string1 = 'Case 1' +string2 = "Case 2" +string3 = 'Case 3' + + diff --git a/tests/fixtures/formats/sample.url b/tests/fixtures/formats/sample.url new file mode 100644 index 0000000000..361d70dbb6 --- /dev/null +++ b/tests/fixtures/formats/sample.url @@ -0,0 +1 @@ +bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter \ No newline at end of file diff --git a/tests/fixtures/formats/sample_data.ods b/tests/fixtures/formats/sample_data.ods new file mode 100644 index 0000000000000000000000000000000000000000..5bcd2bda44433949cc386b3be0bfc7db036108f3 GIT binary patch literal 49626 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%0A3#0NBD8Dr8%^7fPX(Yjg66_s^#sK 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 #[test] fn canonicalize_path() { @@ -17,12 +13,8 @@ fn canonicalize_path() { let mut spam = dirs.test().clone(); spam.push("spam.txt"); -<<<<<<< HEAD - let actual = canonicalize(spam).expect("Failed to canonicalize"); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = canonicalize_with(spam, cwd).expect("Failed to canonicalize"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert!(actual.ends_with("spam.txt")); }); @@ -36,13 +28,9 @@ fn canonicalize_unicode_path() { let mut spam = dirs.test().clone(); spam.push("πŸš’.txt"); -<<<<<<< HEAD - let actual = canonicalize(spam).expect("Failed to canonicalize"); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = canonicalize_with(spam, cwd).expect("Failed to canonicalize"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert!(actual.ends_with("πŸš’.txt")); }); @@ -108,13 +96,9 @@ fn canonicalize_absolute_path_relative_to() { #[test] fn canonicalize_dot() { -<<<<<<< HEAD - let actual = canonicalize(".").expect("Failed to canonicalize"); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = canonicalize_with(".", cwd).expect("Failed to canonicalize"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let expected = std::env::current_dir().expect("Could not get current directory"); assert_eq!(actual, expected); @@ -122,14 +106,10 @@ fn canonicalize_dot() { #[test] fn canonicalize_many_dots() { -<<<<<<< HEAD - let actual = canonicalize("././/.//////./././//.///").expect("Failed to canonicalize"); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = canonicalize_with("././/.//////./././//.///", cwd).expect("Failed to canonicalize"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let expected = std::env::current_dir().expect("Could not get current directory"); assert_eq!(actual, expected); @@ -164,13 +144,8 @@ fn canonicalize_path_with_many_dots_relative_to() { #[test] fn canonicalize_double_dot() { -<<<<<<< HEAD - let actual = canonicalize("..").expect("Failed to canonicalize"); - let cwd = std::env::current_dir().expect("Could not get current directory"); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = canonicalize_with("..", &cwd).expect("Failed to canonicalize"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let expected = cwd .parent() .expect("Could not get parent of current directory"); @@ -210,13 +185,8 @@ fn canonicalize_path_with_many_double_dots_relative_to() { #[test] fn canonicalize_ndots() { -<<<<<<< HEAD - let actual = canonicalize("...").expect("Failed to canonicalize"); - let cwd = std::env::current_dir().expect("Could not get current directory"); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = canonicalize_with("...", &cwd).expect("Failed to canonicalize"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let expected = cwd .parent() .expect("Could not get parent of current directory") @@ -332,12 +302,8 @@ fn canonicalize_unicode_path_with_way_too_many_dots_relative_to_unicode_path_wit fn canonicalize_tilde() { let tilde_path = "~"; -<<<<<<< HEAD - let actual = canonicalize(tilde_path).expect("Failed to canonicalize"); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = canonicalize_with(tilde_path, cwd).expect("Failed to canonicalize"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert!(actual.is_absolute()); assert!(!actual.starts_with("~")); @@ -364,12 +330,8 @@ fn canonicalize_symlink() { let mut symlink_path = dirs.test().clone(); symlink_path.push("link_to_spam.txt"); -<<<<<<< HEAD - let actual = canonicalize(symlink_path).expect("Failed to canonicalize"); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = canonicalize_with(symlink_path, cwd).expect("Failed to canonicalize"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let mut expected = dirs.test().clone(); expected.push("spam.txt"); @@ -448,12 +410,8 @@ fn canonicalize_nested_symlink_within_symlink_dir_relative_to() { fn canonicalize_should_fail() { let path = Path::new("/foo/bar/baz"); // hopefully, this path does not exist -<<<<<<< HEAD - assert!(canonicalize(path).is_err()); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); assert!(canonicalize_with(path, cwd).is_err()); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] diff --git a/tests/path/expand_path.rs b/tests/path/expand_path.rs index 1cc7d91571..24f4eeea9d 100644 --- a/tests/path/expand_path.rs +++ b/tests/path/expand_path.rs @@ -2,29 +2,20 @@ use std::path::PathBuf; use nu_test_support::playground::Playground; -<<<<<<< HEAD -use nu_path::{expand_path, expand_path_with}; - -======= use nu_path::expand_path_with; #[cfg(not(windows))] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn expand_path_with_and_without_relative() { let relative_to = "/foo/bar"; let path = "../.."; let full_path = "/foo/bar/../.."; -<<<<<<< HEAD - assert_eq!(expand_path(full_path), expand_path_with(path, relative_to),); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); assert_eq!( expand_path_with(full_path, cwd), expand_path_with(path, relative_to), ); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -35,20 +26,13 @@ fn expand_path_with_relative() { assert_eq!(PathBuf::from("/"), expand_path_with(path, relative_to),); } -<<<<<<< HEAD -======= #[cfg(not(windows))] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn expand_path_no_change() { let path = "/foo/bar"; -<<<<<<< HEAD - let actual = expand_path(&path); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = expand_path_with(&path, cwd); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual, PathBuf::from(path)); } @@ -59,12 +43,8 @@ fn expand_unicode_path_no_change() { let mut spam = dirs.test().clone(); spam.push("πŸš’.txt"); -<<<<<<< HEAD - let actual = expand_path(spam); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = expand_path_with(spam, cwd); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let mut expected = dirs.test().clone(); expected.push("πŸš’.txt"); @@ -123,25 +103,6 @@ fn expand_absolute_path_relative_to() { } #[test] -<<<<<<< HEAD -fn expand_path_dot() { - let actual = expand_path("."); - let expected = PathBuf::from("."); - - assert_eq!(actual, expected); -} - -#[test] -fn expand_path_many_dots() { - let actual = expand_path("././/.//////./././//.///"); - let expected = PathBuf::from("././././././."); - - assert_eq!(actual, expected); -} - -#[test] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn expand_path_with_dot_relative_to() { Playground::setup("nu_path_test_1", |dirs, _| { let actual = expand_path_with("./spam.txt", dirs.test()); @@ -153,33 +114,6 @@ fn expand_path_with_dot_relative_to() { } #[test] -<<<<<<< HEAD -fn expand_path_double_dot() { - let actual = expand_path(".."); - let expected = PathBuf::from(".."); - - assert_eq!(actual, expected); -} - -#[test] -fn expand_path_dot_double_dot() { - let actual = expand_path("./.."); - let expected = PathBuf::from("./.."); - - assert_eq!(actual, expected); -} - -#[test] -fn expand_path_double_dot_dot() { - let actual = expand_path("../."); - let expected = PathBuf::from(".."); - - assert_eq!(actual, expected); -} - -#[test] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn expand_path_with_many_dots_relative_to() { Playground::setup("nu_path_test_1", |dirs, _| { let actual = expand_path_with("././/.//////./././//.////spam.txt", dirs.test()); @@ -213,26 +147,6 @@ fn expand_path_with_many_double_dots_relative_to() { } #[test] -<<<<<<< HEAD -fn expand_path_ndots() { - let actual = expand_path("..."); - let mut expected = PathBuf::from(".."); - expected.push(".."); - - assert_eq!(actual, expected); -} - -#[test] -fn expand_normal_path_ndots() { - let actual = expand_path("foo/bar/baz/..."); - let expected = PathBuf::from("foo"); - - assert_eq!(actual, expected); -} - -#[test] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn expand_path_with_3_ndots_relative_to() { Playground::setup("nu_path_test_1", |dirs, _| { let actual = expand_path_with("foo/bar/.../spam.txt", dirs.test()); @@ -314,12 +228,8 @@ fn expand_unicode_path_with_way_too_many_dots_relative_to_unicode_path_with_spac fn expand_path_tilde() { let tilde_path = "~"; -<<<<<<< HEAD - let actual = expand_path(tilde_path); -======= let cwd = std::env::current_dir().expect("Could not get current directory"); let actual = expand_path_with(tilde_path, cwd); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert!(actual.is_absolute()); assert!(!actual.starts_with("~")); diff --git a/tests/path/mod.rs b/tests/path/mod.rs new file mode 100644 index 0000000000..2b679c72b6 --- /dev/null +++ b/tests/path/mod.rs @@ -0,0 +1,2 @@ +mod canonicalize; +mod expand_path; diff --git a/tests/plugins/core_inc.rs b/tests/plugins/core_inc.rs new file mode 100644 index 0000000000..af7e261434 --- /dev/null +++ b/tests/plugins/core_inc.rs @@ -0,0 +1,135 @@ +use nu_test_support::fs::Stub::FileWithContent; +use nu_test_support::nu_with_plugins; +use nu_test_support::playground::Playground; + +#[test] +fn can_only_apply_one() { + let actual = nu_with_plugins!( + cwd: "tests/fixtures/formats", + "open cargo_sample.toml | first 1 | inc package.version --major --minor" + ); + + assert!(actual + .err + .contains("Usage: inc field [--major|--minor|--patch]")); +} + +#[test] +fn by_one_with_field_passed() { + Playground::setup("plugin_inc_test_1", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContent( + "sample.toml", + r#" + [package] + edition = "2018" + "#, + )]); + + let actual = nu_with_plugins!( + cwd: dirs.test(), + "open sample.toml | inc package.edition | get package.edition" + ); + + assert_eq!(actual.out, "2019"); + }) +} + +#[test] +fn by_one_with_no_field_passed() { + Playground::setup("plugin_inc_test_2", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContent( + "sample.toml", + r#" + [package] + contributors = "2" + "#, + )]); + + let actual = nu_with_plugins!( + cwd: dirs.test(), + "open sample.toml | get package.contributors | inc" + ); + + assert_eq!(actual.out, "3"); + }) +} + +#[test] +fn semversion_major_inc() { + Playground::setup("plugin_inc_test_3", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContent( + "sample.toml", + r#" + [package] + version = "0.1.3" + "#, + )]); + + let actual = nu_with_plugins!( + cwd: dirs.test(), + "open sample.toml | inc package.version -M | get package.version" + ); + + assert_eq!(actual.out, "1.0.0"); + }) +} + +#[test] +fn semversion_minor_inc() { + Playground::setup("plugin_inc_test_4", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContent( + "sample.toml", + r#" + [package] + version = "0.1.3" + "#, + )]); + + let actual = nu_with_plugins!( + cwd: dirs.test(), + "open sample.toml | inc package.version --minor | get package.version" + ); + + assert_eq!(actual.out, "0.2.0"); + }) +} + +#[test] +fn semversion_patch_inc() { + Playground::setup("plugin_inc_test_5", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContent( + "sample.toml", + r#" + [package] + version = "0.1.3" + "#, + )]); + + let actual = nu_with_plugins!( + cwd: dirs.test(), + "open sample.toml | inc package.version --patch | get package.version" + ); + + assert_eq!(actual.out, "0.1.4"); + }) +} + +#[test] +fn semversion_without_passing_field() { + Playground::setup("plugin_inc_test_6", |dirs, sandbox| { + sandbox.with_files(vec![FileWithContent( + "sample.toml", + r#" + [package] + version = "0.1.3" + "#, + )]); + + let actual = nu_with_plugins!( + cwd: dirs.test(), + "open sample.toml | get package.version | inc --patch" + ); + + assert_eq!(actual.out, "0.1.4"); + }) +} diff --git a/tests/plugins/mod.rs b/tests/plugins/mod.rs new file mode 100644 index 0000000000..23310d10ba --- /dev/null +++ b/tests/plugins/mod.rs @@ -0,0 +1,2 @@ +#[cfg(features = "inc")] +mod core_inc; diff --git a/tests/shell/environment/env.rs b/tests/shell/environment/env.rs index 54102cf391..2d2cb51fed 100644 --- a/tests/shell/environment/env.rs +++ b/tests/shell/environment/env.rs @@ -9,11 +9,7 @@ use serial_test::serial; #[test] fn env_shorthand() { let actual = nu!(cwd: ".", r#" -<<<<<<< HEAD - FOO=bar echo $nu.env.FOO -======= FOO=bar echo $env.FOO ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#); assert_eq!(actual.out, "bar"); } @@ -21,11 +17,7 @@ fn env_shorthand() { #[test] fn env_shorthand_with_equals() { let actual = nu!(cwd: ".", r#" -<<<<<<< HEAD - RUST_LOG=my_module=info $nu.env.RUST_LOG -======= RUST_LOG=my_module=info $env.RUST_LOG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#); assert_eq!(actual.out, "my_module=info"); } @@ -33,11 +25,7 @@ fn env_shorthand_with_equals() { #[test] fn env_shorthand_with_comma_equals() { let actual = nu!(cwd: ".", r#" -<<<<<<< HEAD - RUST_LOG=info,my_module=info $nu.env.RUST_LOG -======= RUST_LOG=info,my_module=info $env.RUST_LOG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#); assert_eq!(actual.out, "info,my_module=info"); } @@ -45,11 +33,7 @@ fn env_shorthand_with_comma_equals() { #[test] fn env_shorthand_with_comma_colons_equals() { let actual = nu!(cwd: ".", r#" -<<<<<<< HEAD - RUST_LOG=info,my_module=info,lib_crate::lib_mod=trace $nu.env.RUST_LOG -======= RUST_LOG=info,my_module=info,lib_crate::lib_mod=trace $env.RUST_LOG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#); assert_eq!(actual.out, "info,my_module=info,lib_crate::lib_mod=trace"); } @@ -57,11 +41,7 @@ fn env_shorthand_with_comma_colons_equals() { #[test] fn env_shorthand_multi_second_with_comma_colons_equals() { let actual = nu!(cwd: ".", r#" -<<<<<<< HEAD - FOO=bar RUST_LOG=info,my_module=info,lib_crate::lib_mod=trace $nu.env.FOO + $nu.env.RUST_LOG -======= FOO=bar RUST_LOG=info,my_module=info,lib_crate::lib_mod=trace $env.FOO + $env.RUST_LOG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#); assert_eq!( actual.out, @@ -72,11 +52,7 @@ fn env_shorthand_multi_second_with_comma_colons_equals() { #[test] fn env_shorthand_multi_first_with_comma_colons_equals() { let actual = nu!(cwd: ".", r#" -<<<<<<< HEAD - RUST_LOG=info,my_module=info,lib_crate::lib_mod=trace FOO=bar $nu.env.FOO + $nu.env.RUST_LOG -======= RUST_LOG=info,my_module=info,lib_crate::lib_mod=trace FOO=bar $env.FOO + $env.RUST_LOG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#); assert_eq!( actual.out, @@ -87,11 +63,7 @@ fn env_shorthand_multi_first_with_comma_colons_equals() { #[test] fn env_shorthand_multi() { let actual = nu!(cwd: ".", r#" -<<<<<<< HEAD - FOO=bar BAR=baz $nu.env.FOO + $nu.env.BAR -======= FOO=bar BAR=baz $env.FOO + $env.BAR ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#); assert_eq!(actual.out, "barbaz"); } diff --git a/tests/shell/environment/mod.rs b/tests/shell/environment/mod.rs index aa208ea7b7..e35eff939e 100644 --- a/tests/shell/environment/mod.rs +++ b/tests/shell/environment/mod.rs @@ -1,10 +1,4 @@ -<<<<<<< HEAD -mod configuration; mod env; -mod in_sync; -======= -mod env; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce mod nu_env; pub mod support { diff --git a/tests/shell/environment/nu_env.rs b/tests/shell/environment/nu_env.rs index 3c354fec22..14cc3b1f29 100644 --- a/tests/shell/environment/nu_env.rs +++ b/tests/shell/environment/nu_env.rs @@ -29,11 +29,7 @@ fn picks_up_env_keys_when_entering_trusted_directory() { let expected = "testvalue"; -<<<<<<< HEAD - let actual = Trusted::in_path(&dirs, || nu!(cwd: dirs.test(), "echo $nu.env.testkey")); -======= let actual = Trusted::in_path(&dirs, || nu!(cwd: dirs.test(), "echo $env.testkey")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.out, expected); }) @@ -67,11 +63,7 @@ fn picks_up_and_lets_go_env_keys_when_entering_trusted_directory_with_implied_cd r#" do {autoenv trust -q foo ; = $nothing } foo -<<<<<<< HEAD - echo $nu.env.testkey"# -======= echo $env.testkey"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "testvalue"); //Assert testkey is gone when leaving foo @@ -81,11 +73,7 @@ fn picks_up_and_lets_go_env_keys_when_entering_trusted_directory_with_implied_cd do {autoenv trust -q foo; = $nothing } ; foo .. -<<<<<<< HEAD - echo $nu.env.testkey -======= echo $env.testkey ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert!(actual.err.contains("Unknown")); @@ -96,13 +84,8 @@ fn picks_up_and_lets_go_env_keys_when_entering_trusted_directory_with_implied_cd do {autoenv trust -q foo; = $nothing } ; do {autoenv trust -q foo/bar; = $nothing } ; foo/bar -<<<<<<< HEAD - echo $nu.env.testkey - echo $nu.env.bar -======= echo $env.testkey echo $env.bar ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert_eq!(actual.out, "testvaluetrue"); @@ -112,11 +95,7 @@ fn picks_up_and_lets_go_env_keys_when_entering_trusted_directory_with_implied_cd r#"autoenv trust -q foo; foo/bar ../.. -<<<<<<< HEAD - echo $nu.env.bar"# -======= echo $env.bar"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert!(actual.err.contains("Unknown")); }); @@ -143,11 +122,7 @@ fn picks_up_script_vars_when_entering_trusted_directory() { let expected = "myval"; -<<<<<<< HEAD - let actual = Trusted::in_path(&dirs, || nu!(cwd: dirs.test(), "echo $nu.env.myscript")); -======= let actual = Trusted::in_path(&dirs, || nu!(cwd: dirs.test(), "echo $env.myscript")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce // scriptvars are not supported // and why is myval expected when myscript is "echo myval" @@ -171,11 +146,7 @@ fn picks_up_env_keys_when_entering_trusted_directory_indirectly() { let actual = Trusted::in_path(&dirs, || { nu!(cwd: dirs.test().join("crates"), r#" cd ../../autoenv_test_3 -<<<<<<< HEAD - echo $nu.env.nu-ver -======= echo $env.nu-ver ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#) }); @@ -355,11 +326,7 @@ fn given_a_hierachy_of_trusted_directories_when_entering_in_any_nested_ones_shou nu!(cwd: dirs.test().parent().unwrap(), r#" do { autoenv trust -q autoenv_test_9/nu_plugin_rb ; = $nothing } # Silence autoenv trust -q message from output cd autoenv_test_9/nu_plugin_rb -<<<<<<< HEAD - echo $nu.env.organization -======= echo $env.organization ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#) }); @@ -390,11 +357,7 @@ fn given_a_hierachy_of_trusted_directories_nested_ones_should_overwrite_variable nu!(cwd: dirs.test().parent().unwrap(), r#" do { autoenv trust -q autoenv_test_10/nu_plugin_rb ; = $nothing } # Silence autoenv trust -q message from output cd autoenv_test_10/nu_plugin_rb -<<<<<<< HEAD - echo $nu.env.organization -======= echo $env.organization ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#) }); @@ -422,11 +385,7 @@ fn local_config_should_not_be_added_when_running_scripts() { FileWithContent( "script.nu", r#"cd foo -<<<<<<< HEAD - echo $nu.env.organization"#, -======= echo $env.organization"#, ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ), ]); @@ -465,11 +424,7 @@ fn given_a_hierachy_of_trusted_directories_going_back_restores_overwritten_varia cd nu_plugin_rb do { rm ../.nu-env | ignore } # By deleting the root nu-env we have guarantees that the variable gets restored (not by autoenv when re-entering) cd .. -<<<<<<< HEAD - echo $nu.env.organization -======= echo $env.organization ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#) }); @@ -495,22 +450,14 @@ fn local_config_env_var_present_and_removed_correctly() { let actual = nu!( cwd: dirs.test(), r#"autoenv trust -q foo; -<<<<<<< HEAD - echo $nu.env.testkey"# -======= echo $env.testkey"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert!(actual.err.contains("Unknown")); //Assert testkey is present in foo let actual = nu!( cwd: dirs.test(), r#"autoenv trust -q foo; cd foo -<<<<<<< HEAD - echo $nu.env.testkey"# -======= echo $env.testkey"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "testvalue"); //Assert testkey is present also in subdirectories @@ -518,22 +465,14 @@ fn local_config_env_var_present_and_removed_correctly() { cwd: dirs.test(), r#"autoenv trust -q foo; cd foo cd bar -<<<<<<< HEAD - echo $nu.env.testkey"# -======= echo $env.testkey"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "testvalue"); //Assert testkey is present also when jumping over foo let actual = nu!( cwd: dirs.test(), r#"autoenv trust -q foo; cd foo/bar -<<<<<<< HEAD - echo $nu.env.testkey"# -======= echo $env.testkey"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "testvalue"); //Assert testkey removed after leaving foo @@ -541,11 +480,7 @@ fn local_config_env_var_present_and_removed_correctly() { cwd: dirs.test(), r#"autoenv trust -q foo; cd foo cd .. -<<<<<<< HEAD - echo $nu.env.testkey"# -======= echo $env.testkey"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert!(actual.err.contains("Unknown")); }); @@ -577,22 +512,14 @@ fn local_config_env_var_gets_overwritten() { let actual = nu!( cwd: dirs.test(), r#"autoenv trust -q foo; -<<<<<<< HEAD - echo $nu.env.overwrite_me"# -======= echo $env.overwrite_me"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert!(actual.err.contains("Unknown")); //Assert overwrite_me is foo in foo let actual = nu!( cwd: dirs.test(), r#"autoenv trust -q foo; cd foo -<<<<<<< HEAD - echo $nu.env.overwrite_me"# -======= echo $env.overwrite_me"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "foo"); //Assert overwrite_me is bar in bar @@ -602,22 +529,14 @@ fn local_config_env_var_gets_overwritten() { autoenv trust -q foo/bar cd foo cd bar -<<<<<<< HEAD - echo $nu.env.overwrite_me"# -======= echo $env.overwrite_me"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "bar"); //Assert overwrite_me is present also when jumping over foo let actual = nu!( cwd: dirs.test(), r#"autoenv trust -q foo; autoenv trust -q foo/bar; cd foo/bar -<<<<<<< HEAD - echo $nu.env.overwrite_me -======= echo $env.overwrite_me ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert_eq!(actual.out, "bar"); @@ -627,11 +546,7 @@ fn local_config_env_var_gets_overwritten() { r#"autoenv trust -q foo; autoenv trust -q foo/bar; cd foo cd bar cd .. -<<<<<<< HEAD - echo $nu.env.overwrite_me"# -======= echo $env.overwrite_me"# ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "foo"); }); diff --git a/tests/shell/mod.rs b/tests/shell/mod.rs index 3ca17e7ea9..0fff95de05 100644 --- a/tests/shell/mod.rs +++ b/tests/shell/mod.rs @@ -1,36 +1,12 @@ -<<<<<<< HEAD -use nu_test_support::fs::AbsolutePath; -use nu_test_support::playground::{says, Playground}; use nu_test_support::{nu, pipeline}; -use hamcrest2::assert_that; -use hamcrest2::prelude::*; - -======= -use nu_test_support::{nu, pipeline}; - ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[cfg(feature = "which-support")] mod environment; mod pipeline; -<<<<<<< HEAD -#[test] -fn runs_configuration_startup_commands() { - Playground::setup("init_config_startup_commands_test", |dirs, nu| { - let file = AbsolutePath::new(dirs.config_fixtures().join("startup.toml")); - - nu.with_config(&file); - - assert_that!(nu.pipeline("hello-world"), says().stdout("Nu World")); - }); -} - -======= //FIXME: jt: we need to focus some fixes on wix as the plugins will differ #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn plugins_are_declared_with_wix() { let actual = nu!( diff --git a/tests/shell/pipeline/commands/external.rs b/tests/shell/pipeline/commands/external.rs index 48cebc7bb8..bd6efaded2 100644 --- a/tests/shell/pipeline/commands/external.rs +++ b/tests/shell/pipeline/commands/external.rs @@ -8,11 +8,7 @@ fn shows_error_for_command_not_found() { "ferris_is_not_here.exe" ); -<<<<<<< HEAD - assert!(actual.err.contains("Command not found")); -======= assert!(!actual.err.is_empty()); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[cfg(feature = "which")] @@ -23,16 +19,10 @@ fn shows_error_for_command_not_found_in_pipeline() { "ferris_is_not_here.exe | echo done" ); -<<<<<<< HEAD - assert!(actual.err.contains("Command not found")); -} - -======= assert!(!actual.err.is_empty()); } #[ignore] // jt: we can't test this using the -c workaround currently ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[cfg(feature = "which")] #[test] fn automatically_change_directory() { @@ -53,11 +43,8 @@ fn automatically_change_directory() { }) } -<<<<<<< HEAD -======= // FIXME: jt: we don't currently support autocd in testing #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn automatically_change_directory_with_trailing_slash_and_same_name_as_command() { use nu_test_support::playground::Playground; @@ -89,29 +76,18 @@ fn execute_binary_in_string() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - let cmd = echo - ^$"($cmd)" '$0' -======= let cmd = "echo" ^$"($cmd)" "$0" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "#); assert_eq!(actual.out, "$0"); } -<<<<<<< HEAD -#[test] -fn redirects_custom_command_external() { - let actual = nu!(cwd: ".", r#"def foo [] { nu --testbin cococo foo bar }; foo | str length "#); -======= //FIXME: jt - this is blocked on https://github.com/nushell/engine-q/issues/875 #[ignore] #[test] fn redirects_custom_command_external() { let actual = nu!(cwd: ".", r#"def foo [] { nu --testbin cococo foo bar }; foo | str length"#); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.out, "8"); } @@ -136,11 +112,7 @@ mod it_evaluation { | sort-by name | get name | each { nu --testbin cococo $it | lines } -<<<<<<< HEAD - | nth 1 -======= | get 1 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -165,11 +137,7 @@ mod it_evaluation { open nu_candies.txt | lines | each { nu --testbin chop $it | lines} -<<<<<<< HEAD - | nth 1 -======= | get 1 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -202,11 +170,7 @@ mod it_evaluation { cwd: dirs.test(), pipeline( r#" open sample.toml -<<<<<<< HEAD - | each { nu --testbin cococo $it.nu_party_venue } -======= | nu --testbin cococo $in.nu_party_venue ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -224,41 +188,25 @@ mod stdin_evaluation { let actual = nu!( cwd: ".", pipeline(r#" -<<<<<<< HEAD - nu --testbin nonu "where's the nuline?" - | length -======= nu --testbin nonu "wheres the nuline?" | length ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); assert_eq!(actual.err, ""); } -<<<<<<< HEAD -======= // FIXME: JT: `lines` doesn't currently support this kind of streaming #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn does_not_block_indefinitely() { let stdout = nu!( cwd: ".", pipeline(r#" -<<<<<<< HEAD - nu --testbin iecho yes - | nu --testbin chop - | nu --testbin chop - | lines - | first 1 -======= ( nu --testbin iecho yes | nu --testbin chop | nu --testbin chop | lines | first 1 ) ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )) .out; @@ -280,11 +228,8 @@ mod external_words { assert_eq!(actual.out, "joturner@foo.bar.baz"); } -<<<<<<< HEAD -======= //FIXME: jt: limitation in testing - can't use single ticks currently #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn no_escaping_for_single_quoted_strings() { let actual = nu!(cwd: ".", r#" @@ -297,12 +242,8 @@ mod external_words { #[rstest::rstest] #[case("sample.toml", r#""sample.toml""#)] #[case("a sample file.toml", r#""a sample file.toml""#)] -<<<<<<< HEAD - #[case("quote'mark.toml", r#""quote'mark.toml""#)] -======= //FIXME: jt: we don't currently support single ticks in tests //#[case("quote'mark.toml", r#""quote'mark.toml""#)] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[cfg_attr( not(target_os = "windows"), case(r#"quote"mark.toml"#, r#"$"quote(char double_quote)mark.toml""#) @@ -456,28 +397,16 @@ mod external_command_arguments { |dirs, sandbox| { sandbox.mkdir("cd"); -<<<<<<< HEAD - sandbox.with_files(vec![EmptyFile("cd/jonathan_likes_cake.txt")]); -======= sandbox.with_files(vec![EmptyFile("cd/jt_likes_cake.txt")]); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce let actual = nu!( cwd: dirs.test(), pipeline( r#" -<<<<<<< HEAD - ^ls $"(pwd)/cd" - "# - )); - - assert_eq!(actual.out, "jonathan_likes_cake.txt"); -======= nu --testbin cococo $"(pwd)/cd" "# )); assert!(actual.out.contains("cd")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce }, ) } @@ -508,13 +437,8 @@ mod external_command_arguments { #[test] fn subcommands_are_sanitized_before_passing_to_subshell() { let actual = nu!( -<<<<<<< HEAD - cwd: ",", - "^echo \"$(ls)\"" -======= cwd: ".", "nu --testbin cococo \"$(ls)\"" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "$(ls)"); @@ -524,13 +448,8 @@ mod external_command_arguments { #[test] fn shell_arguments_are_sanitized_even_if_coming_from_other_commands() { let actual = nu!( -<<<<<<< HEAD - cwd: ",", - "^echo (echo \"a;&$(hello)\")" -======= cwd: ".", "nu --testbin cococo (echo \"a;&$(hello)\")" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce ); assert_eq!(actual.out, "a;&$(hello)"); diff --git a/tests/shell/pipeline/commands/internal.rs b/tests/shell/pipeline/commands/internal.rs index f7167c674b..0766f8ca26 100644 --- a/tests/shell/pipeline/commands/internal.rs +++ b/tests/shell/pipeline/commands/internal.rs @@ -1,8 +1,3 @@ -<<<<<<< HEAD -#[cfg(feature = "which")] -use nu_test_support::fs::Stub::FileWithContent; -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce use nu_test_support::fs::Stub::FileWithContentToBeTrimmed; use nu_test_support::nu; use nu_test_support::pipeline; @@ -28,11 +23,7 @@ fn takes_rows_of_nu_value_strings_and_pipes_it_to_stdin_of_external() { open nu_times.csv | get origin | each { ^echo $it | nu --testbin chop | lines } -<<<<<<< HEAD - | nth 2 -======= | get 2 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -57,11 +48,7 @@ fn treats_dot_dot_as_path_not_range() { r#" mkdir temp; cd temp; -<<<<<<< HEAD - echo (open ../nu_times.csv).name | autoview; -======= echo (open ../nu_times.csv).name.0 | table; ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce cd ..; rmdir temp "# @@ -73,65 +60,6 @@ fn treats_dot_dot_as_path_not_range() { } #[test] -<<<<<<< HEAD -fn tags_dont_persist_through_column_path() { - Playground::setup("dot_dot_dir", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContentToBeTrimmed( - "nu_times.csv", - r#" - name,rusty_luck,origin - Jason,1,Canada - "#, - )]); - - let actual = nu!( - cwd: dirs.test(), pipeline( - r#" - mkdir temp; - cd temp; - let x = (open ../nu_times.csv).name; - $x | tags | get anchor | autoview; - cd ..; - rmdir temp - "# - )); - - // chop will remove the last escaped double quote from \"Estados Unidos\" - assert!(actual.err.contains("isn't a column")); - }) -} - -#[test] -fn tags_persist_through_vars() { - Playground::setup("dot_dot_dir", |dirs, sandbox| { - sandbox.with_files(vec![FileWithContentToBeTrimmed( - "nu_times.csv", - r#" - name,rusty_luck,origin - Jason,1,Canada - "#, - )]); - - let actual = nu!( - cwd: dirs.test(), pipeline( - r#" - mkdir temp; - cd temp; - let x = (open ../nu_times.csv); - $x | tags | get anchor.file | autoview; - cd ..; - rmdir temp - "# - )); - - // chop will remove the last escaped double quote from \"Estados Unidos\" - assert!(actual.out.contains("nu_times.csv")); - }) -} - -#[test] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn subexpression_properly_redirects() { let actual = nu!( cwd: ".", @@ -175,11 +103,7 @@ fn subexpression_handles_dot() { echo (open nu_times.csv) | get name | each { nu --testbin chop $it | lines } -<<<<<<< HEAD - | nth 3 -======= | get 3 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# )); @@ -223,11 +147,8 @@ fn string_interpolation_shorthand_overlap() { assert_eq!(actual.out, "3 + 4 = 7"); } -<<<<<<< HEAD -======= // FIXME: jt - we don't currently have a way to escape the single ticks easily #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn string_interpolation_and_paren() { let actual = nu!( @@ -254,33 +175,6 @@ fn string_interpolation_with_unicode() { } #[test] -<<<<<<< HEAD -fn bignum_large_integer() { - let actual = nu!( - cwd: ".", - r#" - echo 91231720741731287123917 - "# - ); - - assert_eq!(actual.out, "91231720741731287123917"); -} - -#[test] -fn bignum_large_decimal() { - let actual = nu!( - cwd: ".", - r#" - echo 91231720741731287123917.1 - "# - ); - - assert_eq!(actual.out, "91231720741731287123917.1"); -} - -#[test] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn run_custom_command() { let actual = nu!( cwd: ".", @@ -297,11 +191,7 @@ fn run_custom_command_with_flag() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - def foo [--bar:number] { if ($bar | empty?) { echo "empty" } { echo $bar } }; foo --bar 10 -======= def foo [--bar:number] { if ($bar | empty?) { echo "empty" } else { echo $bar } }; foo --bar 10 ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -313,11 +203,7 @@ fn run_custom_command_with_flag_missing() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - def foo [--bar:number] { if ($bar | empty?) { echo "empty" } { echo $bar } }; foo -======= def foo [--bar:number] { if ($bar | empty?) { echo "empty" } else { echo $bar } }; foo ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -357,11 +243,7 @@ fn run_broken_inner_custom_command() { "# ); -<<<<<<< HEAD - assert!(actual.err.contains("not found")); -======= assert!(!actual.err.is_empty()); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -369,11 +251,7 @@ fn run_custom_command_with_rest() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - def rest-me [...rest: string] { echo $rest.1 $rest.0}; rest-me "hello" "world" | to json -======= def rest-me [...rest: string] { echo $rest.1 $rest.0}; rest-me "hello" "world" | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -385,11 +263,7 @@ fn run_custom_command_with_rest_and_arg() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - def rest-me-with-arg [name: string, ...rest: string] { echo $rest.1 $rest.0 $name}; rest-me-with-arg "hello" "world" "yay" | to json -======= def rest-me-with-arg [name: string, ...rest: string] { echo $rest.1 $rest.0 $name}; rest-me-with-arg "hello" "world" "yay" | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -401,11 +275,7 @@ fn run_custom_command_with_rest_and_flag() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - def rest-me-with-flag [--name: string, ...rest: string] { echo $rest.1 $rest.0 $name}; rest-me-with-flag "hello" "world" --name "yay" | to json -======= def rest-me-with-flag [--name: string, ...rest: string] { echo $rest.1 $rest.0 $name}; rest-me-with-flag "hello" "world" --name "yay" | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -425,11 +295,8 @@ fn run_custom_command_with_empty_rest() { assert_eq!(actual.err, r#""#); } -<<<<<<< HEAD -======= //FIXME: jt: blocked on https://github.com/nushell/engine-q/issues/912 #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn run_custom_command_with_rest_other_name() { let actual = nu!( @@ -439,21 +306,13 @@ fn run_custom_command_with_rest_other_name() { greeting:string, ...names:string # All of the names ] { -<<<<<<< HEAD - echo $"($greeting), ($names | sort-by | str collect ' ')" -======= echo $"($greeting), ($names | sort-by | str collect)" ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } say-hello Salutations E D C A B "# ); -<<<<<<< HEAD - assert_eq!(actual.out, r#"Salutations, A B C D E"#); -======= assert_eq!(actual.out, r#"Salutations, ABCDE"#); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce assert_eq!(actual.err, r#""#); } @@ -462,11 +321,7 @@ fn alias_a_load_env() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - def activate-helper [] { [[name, value]; [BOB, SAM]] }; alias activate = load-env (activate-helper); activate; $nu.env.BOB -======= def activate-helper [] { {BOB: SAM} }; alias activate = load-env (activate-helper); activate; $env.BOB ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -496,11 +351,7 @@ fn let_doesnt_leak() { "# ); -<<<<<<< HEAD - assert!(actual.err.contains("unknown variable")); -======= assert!(actual.err.contains("variable not found")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -509,11 +360,7 @@ fn let_env_variable() { cwd: ".", r#" let-env TESTENVVAR = "hello world" -<<<<<<< HEAD - echo $nu.env.TESTENVVAR -======= echo $env.TESTENVVAR ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -526,25 +373,14 @@ fn let_env_hides_variable() { cwd: ".", r#" let-env TESTENVVAR = "hello world" -<<<<<<< HEAD - echo $nu.env.TESTENVVAR - let-env TESTENVVAR = $nothing - echo $nu.env.TESTENVVAR -======= echo $env.TESTENVVAR hide TESTENVVAR echo $env.TESTENVVAR ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert_eq!(actual.out, "hello world"); -<<<<<<< HEAD - assert!(actual.err.contains("error")); - assert!(actual.err.contains("Unknown column")); -======= assert!(actual.err.contains("did you mean")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -553,20 +389,6 @@ fn let_env_hides_variable_in_parent_scope() { cwd: ".", r#" let-env TESTENVVAR = "hello world" -<<<<<<< HEAD - echo $nu.env.TESTENVVAR - do { - let-env TESTENVVAR = $nothing - echo $nu.env.TESTENVVAR - } - echo $nu.env.TESTENVVAR - "# - ); - - assert_eq!(actual.out, "hello worldhello world"); - assert!(actual.err.contains("error")); - assert!(actual.err.contains("Unknown column")); -======= echo $env.TESTENVVAR do { hide TESTENVVAR @@ -578,7 +400,6 @@ fn let_env_hides_variable_in_parent_scope() { assert_eq!(actual.out, "hello world"); assert!(actual.err.contains("did you mean")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -587,13 +408,8 @@ fn unlet_env_variable() { cwd: ".", r#" let-env TEST_VAR = "hello world" -<<<<<<< HEAD - unlet-env TEST_VAR - echo $nu.env.TEST_VAR -======= hide TEST_VAR echo $env.TEST_VAR ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert!(actual.err.contains("did you mean")); @@ -604,20 +420,11 @@ fn unlet_nonexistent_variable() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - unlet-env NONEXISTENT_VARIABLE - "# - ); - - assert!(actual.err.contains("error")); - assert!(actual.err.contains("Not an environment variable")); -======= hide NONEXISTENT_VARIABLE "# ); assert!(actual.err.contains("did not find")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -626,16 +433,6 @@ fn unlet_variable_in_parent_scope() { cwd: ".", r#" let-env DEBUG = "1" -<<<<<<< HEAD - echo $nu.env.DEBUG - do { - let-env DEBUG = "2" - echo $nu.env.DEBUG - unlet-env DEBUG - echo $nu.env.DEBUG - } - echo $nu.env.DEBUG -======= echo $env.DEBUG do { let-env DEBUG = "2" @@ -644,7 +441,6 @@ fn unlet_variable_in_parent_scope() { echo $env.DEBUG } echo $env.DEBUG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -656,11 +452,7 @@ fn let_env_doesnt_leak() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - do { let-env xyz = "my message" }; echo $nu.env.xyz -======= do { let-env xyz = "my message" }; echo $env.xyz ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -672,11 +464,7 @@ fn proper_shadow_let_env_aliases() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - let-env DEBUG = true; echo $nu.env.DEBUG | autoview; do { let-env DEBUG = false; echo $nu.env.DEBUG } | autoview; echo $nu.env.DEBUG -======= let-env DEBUG = true; echo $env.DEBUG | table; do { let-env DEBUG = false; echo $env.DEBUG } | table; echo $env.DEBUG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert_eq!(actual.out, "truefalsetrue"); @@ -687,13 +475,8 @@ fn load_env_variable() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - echo [[name, value]; [TESTENVVAR, "hello world"]] | load-env - echo $nu.env.TESTENVVAR -======= echo {TESTENVVAR: "hello world"} | load-env echo $env.TESTENVVAR ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -705,13 +488,8 @@ fn load_env_variable_arg() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - load-env [[name, value]; [TESTENVVAR, "hello world"]] - echo $nu.env.TESTENVVAR -======= load-env {TESTENVVAR: "hello world"} echo $env.TESTENVVAR ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -719,31 +497,11 @@ fn load_env_variable_arg() { } #[test] -<<<<<<< HEAD -fn load_env_variable_arg_and_stream() { - let actual = nu!( - cwd: ".", - r#" - echo [[name, value]; [TESTVARSTREAM, "true"]] | load-env [[name, value]; [TESTVARARG, "false"]] - echo $nu.env | format "{TESTVARSTREAM} {TESTVARARG}" - "# - ); - - assert_eq!(actual.out, "true false"); -} - -#[test] -======= ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce fn load_env_doesnt_leak() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - do { echo [[name, value]; [xyz, "my message"]] | load-env }; echo $nu.env.xyz -======= do { echo { name: xyz, value: "my message" } | load-env }; echo $env.xyz ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -755,36 +513,23 @@ fn proper_shadow_load_env_aliases() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - let-env DEBUG = true; echo $nu.env.DEBUG | autoview; do { echo [[name, value]; [DEBUG, false]] | load-env; echo $nu.env.DEBUG } | autoview; echo $nu.env.DEBUG -======= let-env DEBUG = true; echo $env.DEBUG | table; do { echo {DEBUG: "false"} | load-env; echo $env.DEBUG } | table; echo $env.DEBUG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert_eq!(actual.out, "truefalsetrue"); } -<<<<<<< HEAD -======= //FIXME: jt: load-env can not currently hide variables because $nothing no longer hides #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn load_env_can_hide_var_envs() { let actual = nu!( cwd: ".", r#" let-env DEBUG = "1" -<<<<<<< HEAD - echo $nu.env.DEBUG - load-env [[name, value]; [DEBUG $nothing]] - echo $nu.env.DEBUG -======= echo $env.DEBUG load-env [[name, value]; [DEBUG $nothing]] echo $env.DEBUG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert_eq!(actual.out, "1"); @@ -792,32 +537,20 @@ fn load_env_can_hide_var_envs() { assert!(actual.err.contains("Unknown column")); } -<<<<<<< HEAD -======= //FIXME: jt: load-env can not currently hide variables because $nothing no longer hides #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn load_env_can_hide_var_envs_in_parent_scope() { let actual = nu!( cwd: ".", r#" let-env DEBUG = "1" -<<<<<<< HEAD - echo $nu.env.DEBUG - do { - load-env [[name, value]; [DEBUG $nothing]] - echo $nu.env.DEBUG - } - echo $nu.env.DEBUG -======= echo $env.DEBUG do { load-env [[name, value]; [DEBUG $nothing]] echo $env.DEBUG } echo $env.DEBUG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert_eq!(actual.out, "11"); @@ -830,11 +563,7 @@ fn proper_shadow_let_aliases() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - let DEBUG = false; echo $DEBUG | autoview; do { let DEBUG = true; echo $DEBUG } | autoview; echo $DEBUG -======= let DEBUG = $false; echo $DEBUG | table; do { let DEBUG = $true; echo $DEBUG } | table; echo $DEBUG ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert_eq!(actual.out, "falsetruefalse"); @@ -848,11 +577,7 @@ fn block_params_override() { [1, 2, 3] | each { |a| echo $it } "# ); -<<<<<<< HEAD - assert!(actual.err.contains("unknown variable")); -======= assert!(actual.err.contains("variable not found")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -860,11 +585,7 @@ fn block_params_override_correct() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - [1, 2, 3] | each { |a| echo $a } | to json -======= [1, 2, 3] | each { |a| echo $a } | to json --raw ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); assert_eq!(actual.out, "[1,2,3]"); @@ -922,11 +643,7 @@ fn argument_subexpression_reports_errors() { "echo (ferris_is_not_here.exe)" ); -<<<<<<< HEAD - assert!(actual.err.contains("Command not found")); -======= assert!(!actual.err.is_empty()); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -960,17 +677,11 @@ fn index_out_of_bounds() { "# ); -<<<<<<< HEAD - assert!(actual.err.contains("unknown row")); -} - -======= assert!(actual.err.contains("too large")); } //FIXME: jt - umm, do we actually want to support this? #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn dash_def() { let actual = nu!( @@ -1024,19 +735,11 @@ fn index_row() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - let foo = [[name]; [joe] [bob]]; echo $foo.1 | to json - "# - ); - - assert_eq!(actual.out, r#"{"name":"bob"}"#); -======= let foo = [[name]; [joe] [bob]]; echo $foo.1 | to json --raw "# ); assert_eq!(actual.out, r#"{"name": "bob"}"#); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -1152,11 +855,7 @@ fn range_with_left_var() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - echo [[size]; [3]] | each { echo $it.size..10 } | math sum -======= ({ size: 3}.size)..10 | math sum ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -1168,11 +867,7 @@ fn range_with_right_var() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - echo [[size]; [30]] | each { echo 4..$it.size } | math sum -======= 4..({ size: 30}.size) | math sum ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce "# ); @@ -1244,19 +939,11 @@ fn filesize_math() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - 100 * 10kb - "# - ); - - assert_eq!(actual.out, "1000.0 KB"); -======= 100 * 10kib "# ); assert_eq!(actual.out, "1000.0 KiB"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce // why 1000.0 KB instead of 1.0 MB? // looks like `byte.get_appropriate_unit(false)` behaves this way } @@ -1270,11 +957,7 @@ fn filesize_math2() { "# ); -<<<<<<< HEAD - assert!(actual.err.contains("Coercion")); -======= assert!(actual.err.contains("doesn't support")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -1282,38 +965,22 @@ fn filesize_math3() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - 100kb / 10 - "# - ); - - assert_eq!(actual.out, "10.0 KB"); -======= 100kib / 10 "# ); assert_eq!(actual.out, "10.0 KiB"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] fn filesize_math4() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - 100kb * 5 - "# - ); - - assert_eq!(actual.out, "500.0 KB"); -======= 100kib * 5 "# ); assert_eq!(actual.out, "500.0 KiB"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -1321,19 +988,11 @@ fn filesize_math5() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - 1001 * 1kb - "# - ); - - assert_eq!(actual.out, "1.0 MB"); -======= 1000 * 1kib "# ); assert_eq!(actual.out, "1000.0 KiB"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -1341,19 +1000,11 @@ fn filesize_math6() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - 1001 * 1mb - "# - ); - - assert_eq!(actual.out, "1.0 GB"); -======= 1000 * 1mib "# ); assert_eq!(actual.out, "1000.0 MiB"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -1361,19 +1012,11 @@ fn filesize_math7() { let actual = nu!( cwd: ".", r#" -<<<<<<< HEAD - 1001 * 1gb - "# - ); - - assert_eq!(actual.out, "1.0 TB"); -======= 1000 * 1gib "# ); assert_eq!(actual.out, "1000.0 GiB"); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -1409,11 +1052,7 @@ fn duration_overflow() { "#) ); -<<<<<<< HEAD - assert!(actual.err.contains("Duration overflow")); -======= assert!(actual.err.contains("duration too large")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -1426,11 +1065,7 @@ fn date_and_duration_overflow() { ); // assert_eq!(actual.err, "overflow"); -<<<<<<< HEAD - assert!(actual.err.contains("Duration and date addition overflow")); -======= assert!(actual.err.contains("duration too large")); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] @@ -1524,23 +1159,8 @@ fn nothing_string_1() { assert_eq!(actual.out, "false"); } -<<<<<<< HEAD -#[test] -fn nothing_string_2() { - let actual = nu!( - cwd: ".", pipeline( - r#" - "" == $nothing - "#) - ); - - assert_eq!(actual.out, "true"); -} - -======= // FIXME: no current way to hide aliases #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn unalias_shadowing() { let actual = nu!( @@ -1558,11 +1178,8 @@ fn unalias_shadowing() { assert_eq!(actual.out, "hello"); } -<<<<<<< HEAD -======= // FIXME: no current way to hide aliases #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn unalias_does_not_escape_scope() { let actual = nu!( @@ -1579,11 +1196,8 @@ fn unalias_does_not_escape_scope() { assert_eq!(actual.out, "hello"); } -<<<<<<< HEAD -======= // FIXME: no current way to hide aliases #[ignore] ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce #[test] fn unalias_hides_alias() { let actual = nu!(cwd: ".", pipeline( @@ -1618,41 +1232,25 @@ mod parse { fn errors_if_flag_passed_is_not_exact() { let actual = nu!(cwd: ".", "debug -ra"); -<<<<<<< HEAD - assert!(actual.err.contains("unexpected flag"),); - - let actual = nu!(cwd: ".", "debug --rawx"); - - assert!(actual.err.contains("unexpected flag"),); -======= assert!(actual.err.contains("unknown flag"),); let actual = nu!(cwd: ".", "debug --rawx"); assert!(actual.err.contains("unknown flag"),); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] fn errors_if_flag_is_not_supported() { let actual = nu!(cwd: ".", "debug --ferris"); -<<<<<<< HEAD - assert!(actual.err.contains("unexpected flag"),); -======= assert!(actual.err.contains("unknown flag"),); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } #[test] fn errors_if_passed_an_unexpected_argument() { let actual = nu!(cwd: ".", "debug ferris"); -<<<<<<< HEAD - assert!(actual.err.contains("unexpected argument"),); -======= assert!(actual.err.contains("extra positional argument"),); ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce } } @@ -1718,20 +1316,12 @@ mod variable_scoping { == "ZZZ" ); test_variable_scope!( -<<<<<<< HEAD - r#" def test [input] { echo [0 1 2] | do { do { if $input == "ZZZ" { echo $input } { echo $input } } } } -======= r#" def test [input] { echo [0 1 2] | do { do { if $input == "ZZZ" { echo $input } else { echo $input } } } } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce test ZZZ "# == "ZZZ" ); test_variable_scope!( -<<<<<<< HEAD - r#" def test [input] { echo [0 1 2] | do { do { if $input == "ZZZ" { echo $input } { echo $input } } } } -======= r#" def test [input] { echo [0 1 2] | do { do { if $input == "ZZZ" { echo $input } else { echo $input } } } } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce test ZZZ "# == "ZZZ" ); @@ -1741,11 +1331,7 @@ mod variable_scoping { == "ZZZ" ); test_variable_scope!( -<<<<<<< HEAD - r#" def test [input] { echo [0 1 2] | do { if $input == $input { echo $input } { echo $input } } } -======= r#" def test [input] { echo [0 1 2] | do { if $input == $input { echo $input } else { echo $input } } } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce test ZZZ "# == "ZZZ" ); @@ -1755,20 +1341,12 @@ mod variable_scoping { == ["ZZZ", "ZZZ", "ZZZ"] ); test_variable_scope_list!( -<<<<<<< HEAD - r#" def test [input] { echo [0 1 2] | each { if $it > 0 {echo $input} {echo $input}} } -======= r#" def test [input] { echo [0 1 2] | each { if $it > 0 {echo $input} else {echo $input}} } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce test ZZZ "# == ["ZZZ", "ZZZ", "ZZZ"] ); test_variable_scope_list!( -<<<<<<< HEAD - r#" def test [input] { echo [0 1 2] | each { if $input == $input {echo $input} {echo $input}} } -======= r#" def test [input] { echo [0 1 2] | each { if $input == $input {echo $input} else {echo $input}} } ->>>>>>> 9259a56a28f1dd3a4b720ad815aa19c6eaf6adce test ZZZ "# == ["ZZZ", "ZZZ", "ZZZ"] ); diff --git a/tests/shell/pipeline/commands/mod.rs b/tests/shell/pipeline/commands/mod.rs new file mode 100644 index 0000000000..5b7aa7e195 --- /dev/null +++ b/tests/shell/pipeline/commands/mod.rs @@ -0,0 +1,2 @@ +mod external; +mod internal; diff --git a/tests/shell/pipeline/mod.rs b/tests/shell/pipeline/mod.rs new file mode 100644 index 0000000000..e8fb3af058 --- /dev/null +++ b/tests/shell/pipeline/mod.rs @@ -0,0 +1,10 @@ +mod commands; + +use nu_test_support::nu; + +#[test] +fn doesnt_break_on_utf8() { + let actual = nu!(cwd: ".", "echo ΓΆ"); + + assert_eq!(actual.out, "ΓΆ", "'{}' should contain ΓΆ", actual.out); +}