From e09b0f90e9c3f985740f50c8ac2cbdb80c20e631 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Mon, 17 Feb 2025 17:43:36 -0500 Subject: [PATCH 1/2] wip: bring in tui-markdown --- Cargo.lock | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + 2 files changed, 286 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5783a54..d74ca30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,19 @@ dependencies = [ "libc", ] +[[package]] +name = "ansi-to-tui" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67555e1f1ece39d737e28c8a017721287753af3f93225e4a445b29ccb0f5912c" +dependencies = [ + "nom", + "ratatui", + "simdutf8", + "smallvec", + "thiserror", +] + [[package]] name = "anstream" version = "0.6.17" @@ -143,12 +156,27 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitcode" version = "0.6.3" @@ -173,6 +201,12 @@ dependencies = [ "syn", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.6.0" @@ -415,7 +449,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags", + "bitflags 2.6.0", "crossterm_winapi", "futures-core", "mio", @@ -544,6 +578,12 @@ dependencies = [ "syn", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.10.7" @@ -713,6 +753,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width 0.1.14", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -925,6 +974,12 @@ version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -968,6 +1023,12 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.0" @@ -990,6 +1051,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1020,6 +1091,28 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "onig" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +dependencies = [ + "bitflags 1.3.2", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1137,6 +1230,19 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "plist" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" +dependencies = [ + "base64", + "indexmap", + "quick-xml", + "serde", + "time", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1152,6 +1258,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -1170,6 +1286,34 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pulldown-cmark" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" +dependencies = [ + "bitflags 2.6.0", + "getopts", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + +[[package]] +name = "quick-xml" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.37" @@ -1215,7 +1359,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cassowary", "compact_str", "crossterm", @@ -1245,7 +1389,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags", + "bitflags 2.6.0", ] [[package]] @@ -1340,7 +1484,7 @@ version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ - "bitflags", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -1359,6 +1503,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1440,6 +1593,7 @@ dependencies = [ "serde_json", "slice-utils", "thiserror", + "tui-markdown", "tui-popup", "tui-prompts", "tui-textarea", @@ -1481,6 +1635,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "siphasher" version = "0.3.11" @@ -1558,6 +1718,28 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syntect" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" +dependencies = [ + "bincode", + "bitflags 1.3.2", + "flate2", + "fnv", + "once_cell", + "onig", + "plist", + "regex-syntax", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", +] + [[package]] name = "thiserror" version = "1.0.65" @@ -1585,10 +1767,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", + "itoa", "num-conv", "powerfmt", "serde", "time-core", + "time-macros", ] [[package]] @@ -1597,6 +1781,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "toml_datetime" version = "0.6.8" @@ -1614,6 +1808,53 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tui-markdown" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf7ca4141b6846fae9ca363e7cf00277978d999bf85bfd40b4f569305994c6b" +dependencies = [ + "ansi-to-tui", + "itertools 0.13.0", + "pretty_assertions", + "pulldown-cmark", + "ratatui", + "rstest", + "syntect", + "tracing", +] + [[package]] name = "tui-popup" version = "0.6.0" @@ -1655,6 +1896,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.13" @@ -1702,6 +1949,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1779,6 +2036,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1885,6 +2151,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 32ceef4..155056b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ slice-utils = { git = "https://dev.zaphar.net/zaphar/slice-cursor-rs.git" } tui-popup = "0.6.0" serde_json = "1.0.133" colorsys = "0.6.7" +tui-markdown = { version = "0.3.1", features = [] } From 5ebdc6e70c2ec1e17b845b2e3aaf51584f239c69 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Mon, 17 Feb 2025 17:55:28 -0500 Subject: [PATCH 2/2] wip: divvy up the help docs --- docs/command.md | 20 ++++++++ docs/edit.md | 31 ++++++++++++ docs/index.md | 124 ++------------------------------------------- docs/intro.md | 23 +++++++++ docs/navigation.md | 50 ++++++++++++++++++ docs/visual.md | 19 +++++++ result | 2 +- src/ui/help/mod.rs | 12 +++++ src/ui/mod.rs | 71 ++++++-------------------- 9 files changed, 176 insertions(+), 176 deletions(-) create mode 100644 docs/command.md create mode 100644 docs/edit.md create mode 100644 docs/intro.md create mode 100644 docs/navigation.md create mode 100644 docs/visual.md create mode 100644 src/ui/help/mod.rs diff --git a/docs/command.md b/docs/command.md new file mode 100644 index 0000000..921c735 --- /dev/null +++ b/docs/command.md @@ -0,0 +1,20 @@ +# Command Mode + +You enter command mode by typing `:` while in navigation mode. You can then +type a command and hit `Enter` to execute it or `Esc` to cancel. + +The currently supported commands are: + +* `write [path]` save the current spreadsheet. If the path is provided it will save it to that path. If omitted it will save to the path you are currently editing. `w` is a shorthand alias for this command. +* `insert-rows [number]` Inserts a row into the sheet at your current row. If the number is provided then inserts that many rows. If omitted then just inserts one. +* `insert-cols [number]` Just line `insert-rows` but for columns. +* `rename-sheet [idx] ` rename a sheet. If the idx is provide then renames that sheet. If omitted then it renames the current sheet. +* `new-sheet [name]` Creates a new sheet. If the name is provided then uses that. If omitted then uses a default sheet name. +* `select-sheet ` Select a sheet by name. +* `edit ` Edit a new spreadsheet at the current path. `e` is a shorthand alias for this command. +* `quit` Quits the application. `q` is a shorthand alias for this command. + + + diff --git a/docs/edit.md b/docs/edit.md new file mode 100644 index 0000000..67c9165 --- /dev/null +++ b/docs/edit.md @@ -0,0 +1,31 @@ +# Edit Mode + +You enter Edit mode by hitting `e` or `i` while in navigation mode. Type +what you want into the cell. + +Starting with: + +* `=` will treat what you type as a formula. +* `$` will treat it as us currency. + +Typing a number will treat the contents as a number. While typing non-numeric +text will treat it as text content. + + + +For the most part this should work the same way you expect a spreadsheet to +work. + +* `Enter` will update the cell contents. +* `Esc` will cancel editing the cell and leave it unedited. +* `Ctrl-p` will paste the range selection if it exists into the cell. + +`Ctrl-r` will enter range select mode when editing a formula. You can navigate +around the sheet and hit space to select that cell in the sheet to set the +start of the range. Navigate some more and hit space to set the end of the +range. + +You can find the functions we support documented here: +[ironcalc docs](https://docs.ironcalc.com/functions/lookup-and-reference.html) + diff --git a/docs/index.md b/docs/index.md index cbf1ad6..c317fa9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -33,123 +33,9 @@ The sheetui user interface is loosely inspired by vim. It is a modal interface that is entirely keyboard driven. At nearly any time you can type `Alt-h` to get some context sensitive help. -### Navigation Mode +### Modal Docs -The interface will start out in navigation mode. You can navigate around the -table and between the sheets using the following keybinds: - -**Cell Navigation** - -* `h`, ⬆️, and `TAB` will move one cell to the left. -* `l` and, ➡️ will move one cell to the right. -* `j`, ⬇️, and `Enter` will move one cell down. -* `k` ⬆️, will move one cell up. -* `d` will delete the contents of the selected cell leaving style untouched -* `D` will delete the contents of the selected cell including any style -* `gg` will go to the top row in the current column - -**Sheet Navigation** - -* `Ctrl-n` moves to the next sheet -* `Ctrl-p` moves to the prev sheet - -Sheet navigation moving will loop around when you reach the ends. - -**Numeric prefixes** - -You can prefix each of the keybinds above with a numeric prefix to do them that -many times. So typing `123h` will move to the left 123 times. Hitting `Esc` -will clear the numeric prefix if you want to cancel it. - -**Modifying the Sheet or Cells** - -* `e` or `i` will enter CellEdit mode for the current cell. -* `Ctrl-h` will shorten the width of the column you are on. -* `Ctrl-l` will lengthen the width of the column you are on. - -**Other Keybindings** - -* `Ctrl-r` will enter range selection mode. -* `v` will enter range selection mode with the start of the range already selected. -* `Ctrl-s` will save the sheet. -* `Ctrl-c`, `y` Copy the cell or range contents. -* `Ctrl-v`, `p` Paste into the sheet. -* `Ctrl-Shift-C` Copy the cell or range formatted content. -* `q` will exit the application. -* `:` will enter CommandMode. - -Range selections made from navigation mode will be available to paste into a Cell Edit. - - - -### CellEdit Mode - -You enter CellEdit mode by hitting `e` or `i` while in navigation mode. Type -what you want into the cell. - -Starting with: - -* `=` will treat what you type as a formula. -* `$` will treat it as us currency. - -Typing a number will treat the contents as a number. While typing non-numeric -text will treat it as text content. - - - -For the most part this should work the same way you expect a spreadsheet to -work. - -* `Enter` will update the cell contents. -* `Esc` will cancel editing the cell and leave it unedited. -* `Ctrl-p` will paste the range selection if it exists into the cell. - -`Ctrl-r` will enter range select mode when editing a formula. You can navigate -around the sheet and hit space to select that cell in the sheet to set the -start of the range. Navigate some more and hit space to set the end of the -range. - -You can find the functions we support documented here: -[ironcalc docs](https://docs.ironcalc.com/functions/lookup-and-reference.html) - -### Command Mode - -You enter command mode by typing `:` while in navigation mode. You can then -type a command and hit `Enter` to execute it or `Esc` to cancel. - -The currently supported commands are: - -* `write [path]` save the current spreadsheet. If the path is provided it will save it to that path. If omitted it will save to the path you are currently editing. `w` is a shorthand alias for this command. -* `insert-rows [number]` Inserts a row into the sheet at your current row. If the number is provided then inserts that many rows. If omitted then just inserts one. -* `insert-cols [number]` Just line `insert-rows` but for columns. -* `rename-sheet [idx] ` rename a sheet. If the idx is provide then renames that sheet. If omitted then it renames the current sheet. -* `new-sheet [name]` Creates a new sheet. If the name is provided then uses that. If omitted then uses a default sheet name. -* `select-sheet ` Select a sheet by name. -* `edit ` Edit a new spreadsheet at the current path. `e` is a shorthand alias for this command. -* `quit` Quits the application. `q` is a shorthand alias for this command. - - - -### Range Select Mode - -Range Select mode copies a range reference for use later or delete a range's contents. You can enter range -select mode from CellEdit mode with `CTRL-r`. - -* `h`, `j`, `k`, `l` will navigate around the sheet. -* `Ctrl-n`, `Ctrl-p` will navigate between sheets. -* `Ctrl-c`, `y` Copy the cell or range contents. -* `Ctrl-Shift-C`, 'Y' Copy the cell or range formatted content. -* `The spacebar will select the start and end of the range respectively. -* `d` will delete the contents of the range leaving any style untouched -* `D` will delete the contents of the range including any style - -When you have selected the end of the range you will exit range select mode and -the range reference will be placed into the cell contents you are editing. - - +* [Navigation](./navigation.md) +* [Edit](./edit.md) +* [Visual](./visual.md) +* [Command](./command.md) diff --git a/docs/intro.md b/docs/intro.md new file mode 100644 index 0000000..8ed16c5 --- /dev/null +++ b/docs/intro.md @@ -0,0 +1,23 @@ +# Intro + +## Supported formats + +Currently we only support the [ironcalc](https://docs.ironcalc.com/) xlsx +features for spreadsheet. I plan to handle csv import and export at some point. +I also might support other export formats as well but for the moment just csv +and it's variants such as tsv are in the roadmap. + +## User Interface + +The sheetui user interface is loosely inspired by vim. It is a modal interface +that is entirely keyboard driven. At nearly any time you can type `Alt-h` to +get some context sensitive help. + +## Modal Docs + +To get help on each modality in command mode `:` type + +* `help navigate` +* `help edit` +* `help command` +* `help visual` diff --git a/docs/navigation.md b/docs/navigation.md new file mode 100644 index 0000000..54ba0ea --- /dev/null +++ b/docs/navigation.md @@ -0,0 +1,50 @@ +# Navigation Mode + +The interface will start out in navigation mode. You can navigate around the +table and between the sheets using the following keybinds: + +## Cell Navigation + +* `h`, ⬆️, and `TAB` will move one cell to the left. +* `l` and, ➡️ will move one cell to the right. +* `j`, ⬇️, and `Enter` will move one cell down. +* `k` ⬆️, will move one cell up. +* `d` will delete the contents of the selected cell leaving style untouched +* `D` will delete the contents of the selected cell including any style +* `gg` will go to the top row in the current column + +## Sheet Navigation + +* `Ctrl-n` moves to the next sheet +* `Ctrl-p` moves to the prev sheet + +Sheet navigation moving will loop around when you reach the ends. + +## Numeric prefixes + +You can prefix each of the keybinds above with a numeric prefix to do them that +many times. So typing `123h` will move to the left 123 times. Hitting `Esc` +will clear the numeric prefix if you want to cancel it. + +**Modifying the Sheet or Cells** + +* `e` or `i` will enter CellEdit mode for the current cell. +* `Ctrl-h` will shorten the width of the column you are on. +* `Ctrl-l` will lengthen the width of the column you are on. + +## Other Keybindings + +* `Ctrl-r` will enter range selection mode. +* `v` will enter range selection mode with the start of the range already selected. +* `Ctrl-s` will save the sheet. +* `Ctrl-c`, `y` Copy the cell or range contents. +* `Ctrl-v`, `p` Paste into the sheet. +* `Ctrl-Shift-C` Copy the cell or range formatted content. +* `q` will exit the application. +* `:` will enter CommandMode. + +Range selections made from navigation mode will be available to paste into a Cell Edit. + + + diff --git a/docs/visual.md b/docs/visual.md new file mode 100644 index 0000000..1a90caa --- /dev/null +++ b/docs/visual.md @@ -0,0 +1,19 @@ +# Range Select Mode + +Range Select mode copies a range reference for use later or delete a range's contents. You can enter range +select mode from CellEdit mode with `CTRL-r`. + +* `h`, `j`, `k`, `l` will navigate around the sheet. +* `Ctrl-n`, `Ctrl-p` will navigate between sheets. +* `Ctrl-c`, `y` Copy the cell or range contents. +* `Ctrl-Shift-C`, 'Y' Copy the cell or range formatted content. +* `The spacebar will select the start and end of the range respectively. +* `d` will delete the contents of the range leaving any style untouched +* `D` will delete the contents of the range including any style + +When you have selected the end of the range you will exit range select mode and +the range reference will be placed into the cell contents you are editing. + + diff --git a/result b/result index eacebb1..774cfe9 120000 --- a/result +++ b/result @@ -1 +1 @@ -/nix/store/k826wsv9zc73jamdff1yl1rky2bw9lc6-sheetui-0.1.0 \ No newline at end of file +/nix/store/mvnsm5ndvx4psah2d3y6yd2vwkypy9m7-sheetui-0.1.0 \ No newline at end of file diff --git a/src/ui/help/mod.rs b/src/ui/help/mod.rs new file mode 100644 index 0000000..898253c --- /dev/null +++ b/src/ui/help/mod.rs @@ -0,0 +1,12 @@ +use ratatui::text::Text; +use tui_markdown; + +pub fn render_topic(topic: &str) -> Text<'static> { + match topic { + "navigate" => tui_markdown::from_str(include_str!("../../../docs/navigation.md")), + "edit" => tui_markdown::from_str(include_str!("../../../docs/edit.md")), + "command" => tui_markdown::from_str(include_str!("../../../docs/command.md")), + "visual" => tui_markdown::from_str(include_str!("../../../docs/visual.md")), + _ => tui_markdown::from_str(include_str!("../../../docs/intro.md")), + } +} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 0f7f110..662426d 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -7,14 +7,12 @@ use anyhow::{anyhow, Result}; use crossterm::event::{self, Event, KeyCode, KeyEventKind, KeyModifiers}; use ironcalc::base::{expressions::types::Area, Model}; use ratatui::{ - buffer::Buffer, - layout::{Constraint, Flex, Layout}, - style::{Modifier, Style}, - widgets::Block, + buffer::Buffer, layout::{Constraint, Flex, Layout}, style::{Modifier, Style}, text::{Line, Text}, widgets::Block }; use tui_prompts::{State, Status, TextPrompt, TextState}; use tui_textarea::{CursorMove, TextArea}; +mod help; mod cmd; pub mod render; #[cfg(test)] @@ -81,7 +79,7 @@ pub struct AppState<'ws> { pub char_queue: Vec, pub range_select: RangeSelection, dirty: bool, - popup: Vec, + popup: Text<'ws>, clipboard: Option, } @@ -296,55 +294,16 @@ impl<'ws> Workspace<'ws> { Ok(None) } - fn render_help_text(&self) -> Vec { + fn render_help_text(&self) -> Text<'static> { // TODO(zaphar): We should be sourcing these from our actual help documentation. // Ideally we would also render the markdown content properly. // https://github.com/zaphar/sheetsui/issues/22 match self.state.modality() { - Modality::Navigate => vec![ - "Navigate Mode:".to_string(), - "* e,i: Enter edit mode for current cell".to_string(), - "* ENTER/RETURN: Go down one cell".to_string(), - "* TAB: Go over one cell".to_string(), - "* h,j,k,l: vim style navigation".to_string(), - "* d: clear cell contents leaving style untouched".to_string(), - "* D: clear cell contents including style".to_string(), - "* CTRl-r: Add a row".to_string(), - "* CTRl-c: Add a column".to_string(), - "* CTRl-l: Grow column width by 1".to_string(), - "* CTRl-h: Shrink column width by 1".to_string(), - "* CTRl-n: Next sheet. Starts over at beginning if at end.".to_string(), - "* CTRl-p: Previous sheet. Starts over at end if at beginning.".to_string(), - "* ALT-h: Previous sheet. Starts over at end if at beginning.".to_string(), - "* q exit".to_string(), - "* Ctrl-S Save sheet".to_string(), - ], - Modality::CellEdit => vec![ - "Edit Mode:".to_string(), - "* ENTER/RETURN: Exit edit mode and save changes".to_string(), - "* Ctrl-r: Enter Range Selection mode".to_string(), - "* v: Enter Range Selection mode with the start of the range already selected" - .to_string(), - "* ESC: Exit edit mode and discard changes".to_string(), - "Otherwise edit as normal".to_string(), - ], - Modality::Command => vec![ - "Command Mode:".to_string(), - "* ESC: Exit command mode".to_string(), - "* CTRL-?: Exit command mode".to_string(), - "* ENTER/RETURN: run command and exit command mode".to_string(), - ], - Modality::RangeSelect => vec![ - "Range Selection Mode:".to_string(), - "* ESC: Exit command mode".to_string(), - "* h,j,k,l: vim style navigation".to_string(), - "* d: delete the contents of the range leaving style untouched".to_string(), - "* D: clear cell contents including style".to_string(), - "* Spacebar: Select start and end of range".to_string(), - "* CTRl-n: Next sheet. Starts over at beginning if at end.".to_string(), - "* CTRl-p: Previous sheet. Starts over at end if at beginning.".to_string(), - ], - _ => vec!["General help".to_string()], + Modality::Navigate => help::render_topic("navigate"), + Modality::CellEdit => help::render_topic("edit"), + Modality::Command => help::render_topic("command"), + Modality::RangeSelect => help::render_topic("visual"), + _ => help::render_topic(""), } } @@ -424,8 +383,8 @@ impl<'ws> Workspace<'ws> { self.load_into(path)?; Ok(None) } - Ok(Some(Cmd::Help(_maybe_topic))) => { - self.enter_dialog_mode(vec!["TODO help topic".to_owned()]); + Ok(Some(Cmd::Help(maybe_topic))) => { + self.enter_dialog_mode(help::render_topic(maybe_topic.unwrap_or(""))); Ok(None) } Ok(Some(Cmd::Write(maybe_path))) => { @@ -515,11 +474,11 @@ impl<'ws> Workspace<'ws> { Ok(None) } Ok(None) => { - self.enter_dialog_mode(vec![format!("Unrecognized commmand {}", cmd_text)]); + self.enter_dialog_mode(vec![Line::from(format!("Unrecognized commmand {}", cmd_text))]); Ok(None) } Err(msg) => { - self.enter_dialog_mode(vec![msg.to_owned()]); + self.enter_dialog_mode(vec![Line::from(msg.to_owned())]); Ok(None) } } @@ -931,8 +890,8 @@ impl<'ws> Workspace<'ws> { self.state.command_state.focus(); } - fn enter_dialog_mode(&mut self, msg: Vec) { - self.state.popup = msg; + fn enter_dialog_mode>>(&mut self, msg: T) { + self.state.popup = msg.into(); self.state.modality_stack.push(Modality::Dialog); }