From 9d46c04917db9e94bc9c41831755fbafde5ccf2e Mon Sep 17 00:00:00 2001 From: Katharina Fey Date: Sun, 22 May 2022 11:17:52 +0200 Subject: [PATCH] novelist: restart project with Rust and Gtk4 --- prototypes/novelist/.envrc | 1 + prototypes/novelist/.gitignore | 1 + .../.gitlab-ci.yml | 0 .../.projectile | 0 prototypes/novelist/Cargo.lock | 699 ++++++++++++++++++ prototypes/novelist/Cargo.toml | 5 + .../{novelist-mode.el => novelist}/LICENSE | 0 .../{novelist-mode.el => novelist}/NOTES | 0 .../{novelist-mode.el => novelist}/README.org | 0 .../assets/early-demo.png | Bin .../assets/icons/128x128.png | Bin .../assets/icons/256x256.png | Bin .../assets/icons/32x32.png | Bin .../assets/icons/64x64.png | Bin .../assets/icons/scalable.svg | 0 .../assets/novelist.png | Bin .../{novelist-mode.el => novelist}/config.el | 0 prototypes/novelist/novelist-data/Cargo.toml | 9 + prototypes/novelist/novelist-data/src/file.rs | 26 + prototypes/novelist/novelist-data/src/lib.rs | 78 ++ prototypes/novelist/novelist-data/src/tags.rs | 101 +++ prototypes/novelist/novelist-gtk/Cargo.toml | 10 + prototypes/novelist/novelist-gtk/src/main.rs | 78 ++ .../novelist/novelist-gtk/src/text_buffer.rs | 57 ++ .../novelist/novelist-gtk/src/text_tags.rs | 10 + .../novelist-mode.el | 0 prototypes/novelist/shell.nix | 17 + 27 files changed, 1092 insertions(+) create mode 100644 prototypes/novelist/.envrc create mode 100644 prototypes/novelist/.gitignore rename prototypes/{novelist-mode.el => novelist}/.gitlab-ci.yml (100%) rename prototypes/{novelist-mode.el => novelist}/.projectile (100%) create mode 100644 prototypes/novelist/Cargo.lock create mode 100644 prototypes/novelist/Cargo.toml rename prototypes/{novelist-mode.el => novelist}/LICENSE (100%) rename prototypes/{novelist-mode.el => novelist}/NOTES (100%) rename prototypes/{novelist-mode.el => novelist}/README.org (100%) rename prototypes/{novelist-mode.el => novelist}/assets/early-demo.png (100%) rename prototypes/{novelist-mode.el => novelist}/assets/icons/128x128.png (100%) rename prototypes/{novelist-mode.el => novelist}/assets/icons/256x256.png (100%) rename prototypes/{novelist-mode.el => novelist}/assets/icons/32x32.png (100%) rename prototypes/{novelist-mode.el => novelist}/assets/icons/64x64.png (100%) rename prototypes/{novelist-mode.el => novelist}/assets/icons/scalable.svg (100%) rename prototypes/{novelist-mode.el => novelist}/assets/novelist.png (100%) rename prototypes/{novelist-mode.el => novelist}/config.el (100%) create mode 100644 prototypes/novelist/novelist-data/Cargo.toml create mode 100644 prototypes/novelist/novelist-data/src/file.rs create mode 100644 prototypes/novelist/novelist-data/src/lib.rs create mode 100644 prototypes/novelist/novelist-data/src/tags.rs create mode 100644 prototypes/novelist/novelist-gtk/Cargo.toml create mode 100644 prototypes/novelist/novelist-gtk/src/main.rs create mode 100644 prototypes/novelist/novelist-gtk/src/text_buffer.rs create mode 100644 prototypes/novelist/novelist-gtk/src/text_tags.rs rename prototypes/{novelist-mode.el => novelist}/novelist-mode.el (100%) create mode 100644 prototypes/novelist/shell.nix diff --git a/prototypes/novelist/.envrc b/prototypes/novelist/.envrc new file mode 100644 index 00000000000..051d09d292a --- /dev/null +++ b/prototypes/novelist/.envrc @@ -0,0 +1 @@ +eval "$(lorri direnv)" diff --git a/prototypes/novelist/.gitignore b/prototypes/novelist/.gitignore new file mode 100644 index 00000000000..eb5a316cbd1 --- /dev/null +++ b/prototypes/novelist/.gitignore @@ -0,0 +1 @@ +target diff --git a/prototypes/novelist-mode.el/.gitlab-ci.yml b/prototypes/novelist/.gitlab-ci.yml similarity index 100% rename from prototypes/novelist-mode.el/.gitlab-ci.yml rename to prototypes/novelist/.gitlab-ci.yml diff --git a/prototypes/novelist-mode.el/.projectile b/prototypes/novelist/.projectile similarity index 100% rename from prototypes/novelist-mode.el/.projectile rename to prototypes/novelist/.projectile diff --git a/prototypes/novelist/Cargo.lock b/prototypes/novelist/Cargo.lock new file mode 100644 index 00000000000..50bf55354eb --- /dev/null +++ b/prototypes/novelist/Cargo.lock @@ -0,0 +1,699 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cairo-rs" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62be3562254e90c1c6050a72aa638f6315593e98c5cdaba9017cedbabf0a5dee" +dependencies = [ + "bitflags", + "cairo-sys-rs", + "glib", + "libc", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "cfg-expr" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e068cb2806bbc15b439846dc16c5f89f8599f2c3e4d73d4449d38f9b2f0b6c5" +dependencies = [ + "smallvec", +] + +[[package]] +name = "field-offset" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" +dependencies = [ + "bitflags", + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk4" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a2fc0bd03d59383fc10b71a8cb731a1fac2998732a36a0c03e9b1de1513218" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk-pixbuf", + "gdk4-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk4-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48a39e34abe35ee2cf54a1e29dd983accecd113ad30bdead5050418fa92f2a1b" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gio" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f132be35e05d9662b9fa0fee3f349c6621f7782e0105917f4cc73c1bf47eceb" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-io", + "gio-sys", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124026a2fa8c33a3d17a3fe59c103f2d9fa5bd92c19e029e037736729abeab" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" +dependencies = [ + "anyhow", + "heck", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "glib-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "gobject-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "graphene-rs" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c54f9fbbeefdb62c99f892dfca35f83991e2cb5b46a8dc2a715e58612f85570" +dependencies = [ + "glib", + "graphene-sys", + "libc", +] + +[[package]] +name = "graphene-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa691fc7337ba1df599afb55c3bcb85c04f1b3f17362570e9bb0ff0d1bc3028a" +dependencies = [ + "glib-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gsk4" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d5a47a78c682bb67496b562495ed84972c0512ba0654888c4dc92b80a85bd3" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk4", + "glib", + "graphene-rs", + "gsk4-sys", + "libc", + "pango", +] + +[[package]] +name = "gsk4-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31d21d7ce02ba261bb24c50c4ab238a10b41a2c97c32afffae29471b7cca69b" +dependencies = [ + "cairo-sys-rs", + "gdk4-sys", + "glib-sys", + "gobject-sys", + "graphene-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk4" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5d40303dabe4608fc260de2bd7563da6f85bc90af956323f0cd8ae0abcfe03" +dependencies = [ + "bitflags", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk-pixbuf", + "gdk4", + "gio", + "glib", + "graphene-rs", + "gsk4", + "gtk4-macros", + "gtk4-sys", + "libc", + "once_cell", + "pango", +] + +[[package]] +name = "gtk4-macros" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f3c4aa605fb3d78205c7aef0eeaa6db61d8cc4dd05a465dc6ffdfdaee84f825" +dependencies = [ + "anyhow", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quick-xml", + "quote", + "syn", +] + +[[package]] +name = "gtk4-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c47c075e8f795c38f6e9a47b51a73eab77b325f83c0154979ed4d4245c36490d" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk4-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "graphene-sys", + "gsk4-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "libc" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "novelist-data" +version = "0.1.0" +dependencies = [ + "serde", + "xml-rs", +] + +[[package]] +name = "novelist-gtk" +version = "0.1.0" +dependencies = [ + "glib", + "gtk4", + "novelist-data", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "pango" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +dependencies = [ + "bitflags", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-xml" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "syn" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04066589568b72ec65f42d65a1a52436e954b168773148893c020269563decf2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "system-deps" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" + +[[package]] +name = "version-compare" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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" + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/prototypes/novelist/Cargo.toml b/prototypes/novelist/Cargo.toml new file mode 100644 index 00000000000..fc05a692486 --- /dev/null +++ b/prototypes/novelist/Cargo.toml @@ -0,0 +1,5 @@ +[workspace] +members = [ + "novelist-gtk", + "novelist-data", +] \ No newline at end of file diff --git a/prototypes/novelist-mode.el/LICENSE b/prototypes/novelist/LICENSE similarity index 100% rename from prototypes/novelist-mode.el/LICENSE rename to prototypes/novelist/LICENSE diff --git a/prototypes/novelist-mode.el/NOTES b/prototypes/novelist/NOTES similarity index 100% rename from prototypes/novelist-mode.el/NOTES rename to prototypes/novelist/NOTES diff --git a/prototypes/novelist-mode.el/README.org b/prototypes/novelist/README.org similarity index 100% rename from prototypes/novelist-mode.el/README.org rename to prototypes/novelist/README.org diff --git a/prototypes/novelist-mode.el/assets/early-demo.png b/prototypes/novelist/assets/early-demo.png similarity index 100% rename from prototypes/novelist-mode.el/assets/early-demo.png rename to prototypes/novelist/assets/early-demo.png diff --git a/prototypes/novelist-mode.el/assets/icons/128x128.png b/prototypes/novelist/assets/icons/128x128.png similarity index 100% rename from prototypes/novelist-mode.el/assets/icons/128x128.png rename to prototypes/novelist/assets/icons/128x128.png diff --git a/prototypes/novelist-mode.el/assets/icons/256x256.png b/prototypes/novelist/assets/icons/256x256.png similarity index 100% rename from prototypes/novelist-mode.el/assets/icons/256x256.png rename to prototypes/novelist/assets/icons/256x256.png diff --git a/prototypes/novelist-mode.el/assets/icons/32x32.png b/prototypes/novelist/assets/icons/32x32.png similarity index 100% rename from prototypes/novelist-mode.el/assets/icons/32x32.png rename to prototypes/novelist/assets/icons/32x32.png diff --git a/prototypes/novelist-mode.el/assets/icons/64x64.png b/prototypes/novelist/assets/icons/64x64.png similarity index 100% rename from prototypes/novelist-mode.el/assets/icons/64x64.png rename to prototypes/novelist/assets/icons/64x64.png diff --git a/prototypes/novelist-mode.el/assets/icons/scalable.svg b/prototypes/novelist/assets/icons/scalable.svg similarity index 100% rename from prototypes/novelist-mode.el/assets/icons/scalable.svg rename to prototypes/novelist/assets/icons/scalable.svg diff --git a/prototypes/novelist-mode.el/assets/novelist.png b/prototypes/novelist/assets/novelist.png similarity index 100% rename from prototypes/novelist-mode.el/assets/novelist.png rename to prototypes/novelist/assets/novelist.png diff --git a/prototypes/novelist-mode.el/config.el b/prototypes/novelist/config.el similarity index 100% rename from prototypes/novelist-mode.el/config.el rename to prototypes/novelist/config.el diff --git a/prototypes/novelist/novelist-data/Cargo.toml b/prototypes/novelist/novelist-data/Cargo.toml new file mode 100644 index 00000000000..3d058530ebc --- /dev/null +++ b/prototypes/novelist/novelist-data/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "novelist-data" +description = "Contain data models for the Novelist application stack" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +xml-rs = "*" \ No newline at end of file diff --git a/prototypes/novelist/novelist-data/src/file.rs b/prototypes/novelist/novelist-data/src/file.rs new file mode 100644 index 00000000000..08e3ee9b6a2 --- /dev/null +++ b/prototypes/novelist/novelist-data/src/file.rs @@ -0,0 +1,26 @@ +use crate::{Buffer, Format, TagEntry}; +use std::sync::{Arc, Mutex}; + +pub fn example() -> Arc { + let content = "Impedit voluptatibus sequi aperiam atque vel vero qui qui. Sit voluptates dicta fugiat repellat qui quia at velit. Reprehenderit qui sit explicabo delectus dolorum necessitatibus adipisci. Minima dignissimos sint et autem aut maiores autem quis. Eum modi et ab. + +Quo eaque et est enim. Laudantium quis quod enim dignissimos. Dolorem perferendis unde eveniet perspiciatis ipsam magnam. Suscipit laboriosam maiores vero illum exercitationem vel. + +Quia atque ipsa ut molestiae non aspernatur. Rem rem delectus occaecati voluptas praesentium et. Distinctio nobis similique et et. Maxime quaerat itaque doloribus. Nesciunt et numquam at voluptate in iste."; + + let first = TagEntry { + start: 27, + end: 57, + style: Format::Bold, + }; + let second = TagEntry { + start: 609, + end: 650, + style: Format::Bold, + }; + + Arc::new(Buffer { + content: Mutex::new(content.into()), + tags: Mutex::new(vec![first, second].into()), + }) +} diff --git a/prototypes/novelist/novelist-data/src/lib.rs b/prototypes/novelist/novelist-data/src/lib.rs new file mode 100644 index 00000000000..e049a065bf9 --- /dev/null +++ b/prototypes/novelist/novelist-data/src/lib.rs @@ -0,0 +1,78 @@ +pub mod file; +mod tags; + +use std::collections::VecDeque; +use std::sync::{Arc, Mutex}; +use tags::RangeState; +pub use tags::{BoundState, Format, TagEntry}; + +/// Main content buffer of a Novelist file +/// +/// The content is a simple text buffer of UTF-8 strings. Formatting +/// tags are applied independently via the tags abstraction. +pub struct Buffer { + // TODO: how does mixed RTL and LTR text get handled here? + pub content: Mutex, + pub tags: Mutex>, +} + +/// A glue trait to connect the storage buffer to a UI toolkit +pub trait PopulateBuffer { + /// Populate a UI text buffer from a storage buffer + fn populate(&self, buffer: &Buffer); +} + +impl Buffer { + /// Create a new empty Buffer + pub fn new() -> Arc { + Arc::new(Self { + content: Mutex::new(String::new()), + tags: Mutex::new(vec![].into()), + }) + } + + /// Pass a UI buffer to populate from this storage buffer + pub fn populate_ui(self: &Arc, hook: &impl PopulateBuffer) { + hook.populate(self) + } + + /// Toggle a style for a particular range of characters + /// + /// This function MUST handle specific corner cases around + /// overlapping ranges. + /// + /// Returns a set of styles that MUST be applied to the TextBuffer + pub fn toggle_style( + self: &Arc, + (start, end): (i32, i32), + style: Format, + ) -> Vec<(i32, i32, Format)> { + // 1. Go through linked list and compare list-pos to new-pos + // 2. If NoOverlap, continue + // 3. If BeforeOverlap, expand start-number + // 4. If FullOverlap, ignore (return) + // 5. If AfterOverlap, expand end-number + // 6. If no match was found: insert && sort + + // The action we would like to apply + let target = TagEntry { start, end, style }; + + // Lock existing tags and iterate through them + let mut tags = self.tags.lock().unwrap(); + for entry in tags.iter_mut() { + // First perform a simple boundry check + match entry.in_range(&target) { + RangeState::Under => continue, + RangeState::Over => break, + RangeState::InRange => {}, + } + + // If full-overlap we invert the desired action + + // Then handle before and after overlapjjjjjjtncthgki.iidukntxgbeubyx.ixptxddcdpexe + + } + + todo!() + } +} diff --git a/prototypes/novelist/novelist-data/src/tags.rs b/prototypes/novelist/novelist-data/src/tags.rs new file mode 100644 index 00000000000..47cdef2bd4a --- /dev/null +++ b/prototypes/novelist/novelist-data/src/tags.rs @@ -0,0 +1,101 @@ +#[derive(Debug)] +pub enum Format { + Bold, + Italics, + BoldItalics, +} + +#[derive(Debug)] +pub struct TagEntry { + pub start: i32, + pub end: i32, + pub style: Format, +} + +/// State differentiator for tag entry bounds +#[derive(Debug, PartialEq)] +pub enum BoundState { + /// Other is before Self + BeforeOverlap, + /// Other is after Self + AfterOverlap, + /// Other is inside Self + FullOverlap, + /// There is no overlap + NoOverlap, +} + +/// Indicate whether a section is in range of a target +#[derive(Debug, PartialEq)] +pub(crate) enum RangeState { + Under, + InRange, + Over, +} + +impl TagEntry { + /// Create a new TagEntry + pub(crate) fn new(start: i32, end: i32, style: Format) -> Self { + Self { start, end, style } + } + + fn test(start: i32, end: i32) -> Self { + Self::new(start, end, Format::Bold) + } + + pub(crate) fn in_range(&self, other: &TagEntry) -> RangeState { + match (self.start, other.start, self.end, other.end) { + (_s1, s2, e1, _e2) if e1 < s2 => RangeState::Under, + (s1, s2, e1, e2) if e1 > s2 && s1 < e2 => RangeState::InRange, + (s1, _s2, _e1, e2) if s1 > e2 => RangeState::Over, + (_, _, _, _) => unreachable!(), + } + } + + /// Compare self bounds to other bounds + pub(crate) fn check_bounds(&self, other: &TagEntry) -> BoundState { + // s1/e1 = self, s2/e2 = other + match (self.start, other.start, self.end, other.end) { + (s1, s2, _e1, e2) if s2 < s1 && e2 >= s1 => BoundState::BeforeOverlap, + (s1, s2, e1, e2) if s2 > s1 && s2 <= e1 && e2 > e1 => BoundState::AfterOverlap, + (s1, s2, e1, e2) if s2 >= s1 && e2 <= e1 => BoundState::FullOverlap, + _ => BoundState::NoOverlap, + } + } +} + +#[test] +fn tag_entry_test1() { + let one = TagEntry::test(0, 9); + let two = TagEntry::test(13, 18); + + let one_two_bound = one.check_bounds(&two); + assert_eq!(one_two_bound, BoundState::NoOverlap); +} + +#[test] +fn tag_entry_test2() { + let one = TagEntry::test(0, 9); + let two = TagEntry::test(8, 12); + + let one_two_bound = one.check_bounds(&two); + assert_eq!(one_two_bound, BoundState::AfterOverlap); +} + +#[test] +fn tag_entry_test3() { + let one = TagEntry::test(8, 12); + let two = TagEntry::test(4, 8); + + let one_two_bound = one.check_bounds(&two); + assert_eq!(one_two_bound, BoundState::BeforeOverlap); +} + +#[test] +fn tag_entry_test4() { + let one = TagEntry::test(9, 12); + let two = TagEntry::test(4, 8); + + let one_two_bound = one.check_bounds(&two); + assert_eq!(one_two_bound, BoundState::NoOverlap); +} diff --git a/prototypes/novelist/novelist-gtk/Cargo.toml b/prototypes/novelist/novelist-gtk/Cargo.toml new file mode 100644 index 00000000000..82021ad4779 --- /dev/null +++ b/prototypes/novelist/novelist-gtk/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "novelist-gtk" +description = "Novest Gtk application interface" +version = "0.1.0" +edition = "2021" + +[dependencies] +novelist-data = { path = "../novelist-data" } +gtk4 = "*" +glib = "*" \ No newline at end of file diff --git a/prototypes/novelist/novelist-gtk/src/main.rs b/prototypes/novelist/novelist-gtk/src/main.rs new file mode 100644 index 00000000000..a57124d0fb7 --- /dev/null +++ b/prototypes/novelist/novelist-gtk/src/main.rs @@ -0,0 +1,78 @@ +mod text_buffer; +mod text_tags; + +use gtk4::gio::{SimpleAction, SimpleActionGroup}; +use gtk4::prelude::*; +use gtk4::{Application, ApplicationWindow, TextView, WrapMode}; +use novelist_data::Format; +use std::sync::Arc; + +fn main() { + let app = Application::builder() + .application_id("de.spacekookie.novelist") + .build(); + + app.connect_activate(|app| { + // We create the main window. + let window = ApplicationWindow::builder() + .application(app) + .default_width(800) + .default_height(600) + .title("Novelist") + .build(); + + // Make Novelist use a light theme (TODO: make this work) + // window.settings().set_gtk_application_prefer_dark_theme(false); + + let text_tag_table = text_tags::generate_table(); + let novelist_buffer = novelist_data::file::example(); + let text_buffer = text_buffer::from_store(&text_tag_table, &novelist_buffer); + + let indent = 48; + let margin = 32; + + let text_view = TextView::with_buffer(&text_buffer); + text_view.set_accepts_tab(false); + text_view.set_indent(indent); + text_view.set_bottom_margin(indent); + text_view.set_top_margin(indent); + text_view.set_left_margin(margin); + text_view.set_right_margin(margin); + text_view.set_wrap_mode(WrapMode::Word); + + let bold_action = SimpleAction::new("make-bold", None); + let text_buffer2 = text_buffer.clone(); + let text_buffer3 = text_buffer.clone(); + let novelist_buffer2 = Arc::clone(&novelist_buffer); + bold_action.connect_activate(move |_, _| { + if let Some((start, end)) = text_buffer2.selection_bounds() { + novelist_buffer2.toggle_style((start.offset(), end.offset()), Format::Bold); + + println!("Making text {}-{} bold...", start.offset(), end.offset()); + text_buffer2.apply_tag_by_name("bold", &start, &end); + } + }); + + let save_action = SimpleAction::new("save", None); + save_action.connect_activate(move |_, _| { + let markup = + text_buffer3.text(&text_buffer.start_iter(), &text_buffer.end_iter(), true); + println!("=== SAVING ===\n{}", markup); + }); + + let action_group = SimpleActionGroup::new(); + action_group.add_action(&bold_action); + action_group.add_action(&save_action); + window.insert_action_group("textbuf", Some(&action_group)); + + window.set_child(Some(&text_view)); + window.show(); + }); + + app.connect_startup(|app| { + app.set_accels_for_action("textbuf.make-bold", &["b"]); + app.set_accels_for_action("textbuf.save", &["s"]); + }); + + app.run(); +} diff --git a/prototypes/novelist/novelist-gtk/src/text_buffer.rs b/prototypes/novelist/novelist-gtk/src/text_buffer.rs new file mode 100644 index 00000000000..06dbb111b77 --- /dev/null +++ b/prototypes/novelist/novelist-gtk/src/text_buffer.rs @@ -0,0 +1,57 @@ +//! A text buffer abstraction +//! +//! Because of the separation between novelist-data and novelist-gtk +//! the storage buffer can't rely on the Gtk buffer to fill data and +//! set tag data. This module wraps this relationship + +use gtk4::{prelude::TextBufferExt, TextBuffer, TextTagTable}; +use novelist_data::{Buffer, Format, PopulateBuffer, TagEntry}; +use std::sync::Arc; + +pub struct GtkBuffer(TextBuffer); + +impl GtkBuffer { + pub fn new(tb: TextBuffer) -> Self { + Self(tb) + } + + pub fn consume(self) -> TextBuffer { + self.0 + } +} + +impl PopulateBuffer for GtkBuffer { + fn populate(&self, storage: &Buffer) { + let content = storage.content.lock().unwrap(); + + self.0.set_text(&content); + storage + .tags + .lock() + .unwrap() + .iter() + .for_each(|TagEntry { start, end, style }| { + self.0.apply_tag_by_name( + match style { + Format::Bold => "bold", + Format::Italics => "italics", + _ => unimplemented!(), + }, + &self.0.iter_at_offset(*start), + &self.0.iter_at_offset(*end), + ) + }) + } +} + +/// Create an empty text buffer +pub fn empty(text_tag_table: &TextTagTable) -> TextBuffer { + TextBuffer::new(Some(&text_tag_table)) +} + +/// Load a text buffer from a store +pub fn from_store(text_tag_table: &TextTagTable, buffer: &Arc) -> TextBuffer { + let gtk_buffer = GtkBuffer(empty(text_tag_table)); + buffer.populate_ui(>k_buffer); + gtk_buffer.0 +} diff --git a/prototypes/novelist/novelist-gtk/src/text_tags.rs b/prototypes/novelist/novelist-gtk/src/text_tags.rs new file mode 100644 index 00000000000..09136669776 --- /dev/null +++ b/prototypes/novelist/novelist-gtk/src/text_tags.rs @@ -0,0 +1,10 @@ +use gtk4::{prelude::TextTagExt, TextTag, TextTagTable}; + +/// Generate a table of text tags used in novelist +pub fn generate_table() -> TextTagTable { + let text_tag_table = TextTagTable::new(); + let bold = TextTag::new(Some("bold")); + bold.set_weight(600); + text_tag_table.add(&bold); + text_tag_table +} diff --git a/prototypes/novelist-mode.el/novelist-mode.el b/prototypes/novelist/novelist-mode.el similarity index 100% rename from prototypes/novelist-mode.el/novelist-mode.el rename to prototypes/novelist/novelist-mode.el diff --git a/prototypes/novelist/shell.nix b/prototypes/novelist/shell.nix new file mode 100644 index 00000000000..d6347e3864e --- /dev/null +++ b/prototypes/novelist/shell.nix @@ -0,0 +1,17 @@ +with import {}; + +stdenv.mkDerivation { + name = "novelist"; + buildInputs = with pkgs; [ + rustc cargo rust-analyzer rustfmt clangStdenv + pkg-config + + atk + cairo + gdk-pixbuf + gdk-pixbuf-xlib + glib + gtk4 + pango + ]; +}