Compare commits
31 Commits
main
...
ui-pass-cw
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ba880bc7e | |||
| 6a4957588d | |||
| f4242f7749 | |||
| fd3c8fb204 | |||
| fd9d47f0c0 | |||
| d53ef9aa1b | |||
| a29ae43e84 | |||
| 41a9a2a3bf | |||
| 7bf6c3299c | |||
| 90c10d2a16 | |||
| 2dcf0529d1 | |||
| f740ff347b | |||
| 9b86553513 | |||
| 365940267f | |||
| b426b88b79 | |||
| bdf942371c | |||
| b62dce631f | |||
| 1546eb1028 | |||
| 4f3aebe64f | |||
| 413500dad3 | |||
| b0064c2f69 | |||
| 0f055603a2 | |||
| 094ac92fe4 | |||
| 3b8e407632 | |||
| d2f5823594 | |||
| be9981291c | |||
| 500a329dea | |||
| 70e9f79c8a | |||
| 13a405a801 | |||
| a6d2fb9e31 | |||
| 8b71af06a8 |
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/target
|
||||
.qtcreator
|
||||
.idea
|
||||
**/target/**
|
||||
**/.qtcreator/**
|
||||
**/.idea/**
|
||||
**/*.autosave/**
|
||||
547
Cargo.lock
generated
547
Cargo.lock
generated
@ -2,12 +2,65 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
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.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.16"
|
||||
@ -19,13 +72,34 @@ dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clang-format"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "696283b40e1a39d208ee614b92e5f6521d16962edeb47c48372585ec92419943"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags 1.3.2",
|
||||
"strsim 0.8.0",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -45,7 +119,7 @@ checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"strsim 0.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -62,6 +136,10 @@ dependencies = [
|
||||
"cxx-qt",
|
||||
"cxx-qt-build",
|
||||
"cxx-qt-lib",
|
||||
"dirs",
|
||||
"log",
|
||||
"structopt",
|
||||
"syntect",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -83,6 +161,15 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.148"
|
||||
@ -106,7 +193,7 @@ dependencies = [
|
||||
"codespan-reporting",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -120,7 +207,7 @@ dependencies = [
|
||||
"cxx-qt-macro",
|
||||
"qt-build-utils",
|
||||
"static_assertions",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -152,7 +239,7 @@ dependencies = [
|
||||
"indoc",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -175,7 +262,7 @@ checksum = "58a4fe02c0604eda28c605792f5ba0d0251b4947f8f0fc43e55b61c06b2b8ec6"
|
||||
dependencies = [
|
||||
"cxx-qt-gen",
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -184,11 +271,11 @@ version = "1.0.148"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40399fddbf3977647bfff7453dacffc6b5701b19a282a283369a870115d0a049"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap 4.5.32",
|
||||
"codespan-reporting",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -206,7 +293,37 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -215,12 +332,79 @@ version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.6"
|
||||
@ -251,12 +435,28 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.10"
|
||||
@ -266,6 +466,18 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@ -278,6 +490,15 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@ -288,6 +509,95 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[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 = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"indexmap",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[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 1.0.109",
|
||||
"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.94"
|
||||
@ -304,10 +614,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efb239fdd8c036fabb95364320041ef68197cd4ab971bb3b4ca3ea0b7b93d12c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"versions",
|
||||
]
|
||||
|
||||
[[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.40"
|
||||
@ -317,6 +636,23 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.20"
|
||||
@ -329,6 +665,15 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[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 = "serde"
|
||||
version = "1.0.219"
|
||||
@ -346,7 +691,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -373,12 +718,53 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
|
||||
dependencies = [
|
||||
"clap 2.34.0",
|
||||
"lazy_static",
|
||||
"structopt-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
@ -390,6 +776,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 1.0.69",
|
||||
"walkdir",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
@ -399,13 +807,31 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -416,7 +842,49 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -437,6 +905,12 @@ version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
@ -453,6 +927,38 @@ dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[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-util"
|
||||
version = "0.1.9"
|
||||
@ -462,6 +968,12 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[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 = "windows-sys"
|
||||
version = "0.59.0"
|
||||
@ -534,3 +1046,12 @@ name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
@ -6,7 +6,11 @@ edition = "2024"
|
||||
[dependencies]
|
||||
cxx = "1.0.95"
|
||||
cxx-qt = "0.7"
|
||||
cxx-qt-lib = { version="0.7", features = ["qt_full"] }
|
||||
cxx-qt-lib = { version="0.7", features = ["qt_full", "qt_gui"] }
|
||||
log = { version = "0.4.27", features = [] }
|
||||
dirs = "6.0.0"
|
||||
syntect = "5.2.0"
|
||||
structopt = "0.3.26"
|
||||
|
||||
[build-dependencies]
|
||||
# The link_qt_object_files feature is required for statically linking Qt 6.
|
||||
|
||||
31
README.md
31
README.md
@ -5,7 +5,7 @@ CLIDE is an IDE written in Rust that supports both full and headless Linux envir
|
||||
The following packages must be installed before the application will build.
|
||||
|
||||
```bash
|
||||
sudo apt install qt6-base-dev qt6-declarative-dev qt6-tools-dev qml6-module-qtquick-controls qml6-module-qtquick-layouts qml6-module-qtquick-window qml6-module-qtqml-workerscript qml6-module-qtquick-templates qml6-module-qtquick
|
||||
sudo apt install qt6-base-dev qt6-declarative-dev qt6-tools-dev qml6-module-qtquick-controls qml6-module-qtquick-layouts qml6-module-qtquick-window qml6-module-qtqml-workerscript qml6-module-qtquick-templates qml6-module-qtquick qml6-module-qtquick-dialogs qt6-svg-dev
|
||||
```
|
||||
|
||||
And of course, [Rust](https://www.rust-lang.org/tools/install).
|
||||
@ -22,10 +22,39 @@ The [Qt Installer](https://www.qt.io/download-qt-installer) will provide the lat
|
||||
If using RustRover be sure to set your QML binaries path in the settings menu.
|
||||
If Qt was installed to its default directory this will be `$HOME/Qt/6.8.3/gcc_64/bin/`.
|
||||
|
||||
Viewing documentation in the web browser is possible, but you will end up in a mess of tabs.
|
||||
Using Qt Assistant is recommended. It comes with Qt6 when installed. Run the following command to start it.
|
||||
|
||||
```bash
|
||||
nohup $HOME/Qt/6.8.3/gcc_64/bin/assistant > /dev/null 2>&1 &
|
||||
```
|
||||
|
||||
If you are looking for an include path from Qt
|
||||
|
||||
```bash
|
||||
find /usr/include/x86_64-linux-gnu/qt6/ -name QFile*
|
||||
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtWidgets/QFileIconProvider
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtWidgets/QFileDialog
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtGui/QFileSystemModel
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtGui/QFileOpenEvent
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtCore/QFile
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtCore/QFileDevice
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtCore/QFileSystemWatcher
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtCore/QFileInfoList
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtCore/QFileInfo
|
||||
/usr/include/x86_64-linux-gnu/qt6/QtCore/QFileSelector
|
||||
```
|
||||
|
||||
This helped find that QFileSystemModel is in QtGui and not QtCore.
|
||||
|
||||
### Resources
|
||||
|
||||
Some helpful links for reading up on QML if you're just getting started.
|
||||
|
||||
* [Rust Crates - cxx-qt](https://docs.rs/releases/search?query=cxx_qt)
|
||||
* [QML Reference](https://doc.qt.io/qt-6/qmlreference.html)
|
||||
* [QML Coding Conventions](https://doc.qt.io/qt-6/qml-codingconventions.html)
|
||||
* [All QML Controls Types](https://doc.qt.io/qt-6/qtquick-controls-qmlmodule.html)
|
||||
* [KDAB CXX-Qt Book](https://kdab.github.io/cxx-qt/book/)
|
||||
* [github.com/KDAB/cxx-qt](https://github.com/KDAB/cxx-qt)
|
||||
|
||||
41
build.rs
41
build.rs
@ -1,21 +1,28 @@
|
||||
use cxx_qt_build::{CxxQtBuilder, QmlModule};
|
||||
|
||||
fn main() {
|
||||
CxxQtBuilder::new()
|
||||
// Link Qt's Network library
|
||||
// - Qt Core is always linked
|
||||
// - Qt Gui is linked by enabling the qt_gui Cargo feature of cxx-qt-lib.
|
||||
// - Qt Qml is linked by enabling the qt_qml Cargo feature of cxx-qt-lib.
|
||||
// - Qt Qml requires linking Qt Network on macOS
|
||||
.qt_module("Network")
|
||||
.qml_module(QmlModule {
|
||||
uri: "test",
|
||||
rust_files: &["src/main.rs"],
|
||||
qml_files: &["qml/main.qml",
|
||||
"qml/Menu/ClideMenu.qml",
|
||||
"qml/Menu/ClideMenuBar.qml",
|
||||
"qml/Menu/ClideMenuBarItem.qml"],
|
||||
..Default::default()
|
||||
})
|
||||
.build();
|
||||
CxxQtBuilder::new()
|
||||
// Link Qt's Network library
|
||||
// - Qt Core is always linked
|
||||
// - Qt Gui is linked by enabling the qt_gui Cargo feature of cxx-qt-lib.
|
||||
// - Qt Qml is linked by enabling the qt_qml Cargo feature of cxx-qt-lib.
|
||||
// - Qt Qml requires linking Qt Network on macOS
|
||||
.qt_module("Network")
|
||||
.qt_module("Gui")
|
||||
.qt_module("Svg")
|
||||
.qt_module("Xml")
|
||||
.qml_module(QmlModule {
|
||||
uri: "clide.module",
|
||||
rust_files: &["src/gui/colors.rs", "src/gui/filesystem.rs"],
|
||||
qml_files: &[
|
||||
"qml/main.qml",
|
||||
"qml/ClideAboutWindow.qml",
|
||||
"qml/ClideTreeView.qml",
|
||||
"qml/ClideProjectView.qml",
|
||||
"qml/ClideEditor.qml",
|
||||
"qml/ClideMenuBar.qml",
|
||||
],
|
||||
..Default::default()
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
38
icons/folder_closed.svg
Normal file
38
icons/folder_closed.svg
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
viewBox="-10 0 1792 1792"
|
||||
id="svg51"
|
||||
sodipodi:docname="folder_closed.svg"
|
||||
width="1792"
|
||||
height="1792"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs55" />
|
||||
<sodipodi:namedview
|
||||
id="namedview53"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.45033482"
|
||||
inkscape:cx="842.70632"
|
||||
inkscape:cy="896"
|
||||
inkscape:window-width="1846"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg51" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m 1718,672 v 704 q 0,92 -66,158 -66,66 -158,66 H 278 q -92,0 -158,-66 -66,-66 -66,-158 V 416 q 0,-92 66,-158 66,-66 158,-66 h 320 q 92,0 158,66 66,66 66,158 v 32 h 672 q 92,0 158,66 66,66 66,158 z"
|
||||
id="path49" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
38
icons/folder_open.svg
Normal file
38
icons/folder_open.svg
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
viewBox="-10 0 1792 1792"
|
||||
id="svg139"
|
||||
sodipodi:docname="folder_open.svg"
|
||||
width="1792"
|
||||
height="1792"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs143" />
|
||||
<sodipodi:namedview
|
||||
id="namedview141"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.24358259"
|
||||
inkscape:cx="149.84651"
|
||||
inkscape:cy="1098.1901"
|
||||
inkscape:window-width="1846"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg139" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M 1590,1376 V 672 q 0,-40 -28,-68 -28,-28 -68,-28 H 790 q -40,0 -68,-28 -28,-28 -28,-68 v -64 q 0,-40 -28,-68 -28,-28 -68,-28 H 278 q -40,0 -68,28 -28,28 -28,68 v 960 q 0,40 28,68 28,28 68,28 h 1216 q 40,0 68,-28 28,-28 28,-68 z m 128,-704 v 704 q 0,92 -66,158 -66,66 -158,66 H 278 q -92,0 -158,-66 -66,-66 -66,-158 V 416 q 0,-92 66,-158 66,-66 158,-66 h 320 q 92,0 158,66 66,66 66,158 v 32 h 672 q 92,0 158,66 66,66 66,158 z"
|
||||
id="path137" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
38
icons/generic_file.svg
Normal file
38
icons/generic_file.svg
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.1"
|
||||
viewBox="-10 0 1792 1792"
|
||||
id="svg147"
|
||||
sodipodi:docname="generic_file.svg"
|
||||
width="1792"
|
||||
height="1792"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs151" />
|
||||
<sodipodi:namedview
|
||||
id="namedview149"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.12179129"
|
||||
inkscape:cx="-578.85911"
|
||||
inkscape:cy="1687.3127"
|
||||
inkscape:window-width="1846"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg147" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m 1586,476 q 14,14 28,36 H 1142 V 40 q 22,14 36,28 z m -476,164 h 544 v 1056 q 0,40 -28,68 -28,28 -68,28 H 214 q -40,0 -68,-28 -28,-28 -28,-68 V 96 Q 118,56 146,28 174,0 214,0 h 800 v 544 q 0,40 28,68 28,28 68,28 z m 160,736 v -64 q 0,-14 -9,-23 -9,-9 -23,-9 H 534 q -14,0 -23,9 -9,9 -9,23 v 64 q 0,14 9,23 9,9 23,9 h 704 q 14,0 23,-9 9,-9 9,-23 z m 0,-256 v -64 q 0,-14 -9,-23 -9,-9 -23,-9 H 534 q -14,0 -23,9 -9,9 -9,23 v 64 q 0,14 9,23 9,9 23,9 h 704 q 14,0 23,-9 9,-9 9,-23 z m 0,-256 v -64 q 0,-14 -9,-23 -9,-9 -23,-9 H 534 q -14,0 -23,9 -9,9 -9,23 v 64 q 0,14 9,23 9,9 23,9 h 704 q 14,0 23,-9 9,-9 9,-23 z"
|
||||
id="path145" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
BIN
icons/kilroy-256.png
Normal file
BIN
icons/kilroy-256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
73
qml/ClideAboutWindow.qml
Normal file
73
qml/ClideAboutWindow.qml
Normal file
@ -0,0 +1,73 @@
|
||||
// TODO: Header
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Basic
|
||||
|
||||
import clide.module 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: root
|
||||
width: 450
|
||||
height: 350
|
||||
// Create the window with no frame and keep it on top.
|
||||
flags: Qt.Window | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
|
||||
color: RustColors.gutter
|
||||
|
||||
// Hide the window when it loses focus.
|
||||
onActiveChanged: {
|
||||
if (!active) {
|
||||
root.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Kilroy logo.
|
||||
Image {
|
||||
id: logo
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 20
|
||||
|
||||
source: "../icons/kilroy-256.png"
|
||||
sourceSize.width: 80
|
||||
sourceSize.height: 80
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
smooth: true
|
||||
antialiasing: true
|
||||
asynchronous: true
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
anchors.top: logo.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 20
|
||||
|
||||
TextArea {
|
||||
selectedTextColor: RustColors.editor_highlighted_text
|
||||
selectionColor: RustColors.editor_highlight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
textFormat: Text.RichText
|
||||
|
||||
text: qsTr("<h3>About CLIDE</h3>"
|
||||
+ "<p>A simple text editor written in Rust and QML using CXX-Qt.</p>"
|
||||
+ "<p>Personal website <a href=\"http://shaunreed.com\">shaunreed.com</a></p>"
|
||||
+ "<p>Project notes <a href=\"http://knoats.com\">knoats.com</a></p>"
|
||||
+ "<p>This project is developed at <a href=\"http://git.shaunreed.com/shaunrd0/clide\">git.shaunreed.com</a></p>"
|
||||
+ "<p><a href=\"https://github.com/KDAB/cxx-qt\">KDAB CXX-Qt repository</a></p>"
|
||||
+ "<p>Copyright (C) 2025 Shaun Reed, all rights reserved.</p>")
|
||||
color: RustColors.editor_text
|
||||
wrapMode: Text.WordWrap
|
||||
readOnly: true
|
||||
antialiasing: true
|
||||
background: null
|
||||
|
||||
onLinkActivated: function (link) {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
206
qml/ClideEditor.qml
Normal file
206
qml/ClideEditor.qml
Normal file
@ -0,0 +1,206 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import clide.module 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
orientation: Qt.Vertical
|
||||
|
||||
// The path to the file to show in the text editor.
|
||||
// This is updated by a signal caught within ClideProjectView.
|
||||
// Initialized by the Default trait for the Rust QML singleton FileSystem.
|
||||
required property string filePath;
|
||||
|
||||
// Customized handle to drag between the Editor and the Console.
|
||||
handle: Rectangle {
|
||||
border.color: SplitHandle.pressed ? RustColors.pressed : SplitHandle.hovered ? RustColors.hovered : RustColors.gutter
|
||||
color: SplitHandle.pressed ? RustColors.pressed : SplitHandle.hovered ? RustColors.hovered : RustColors.gutter
|
||||
implicitHeight: 8
|
||||
radius: 2.5
|
||||
|
||||
// Execute these behaviors when the color is changed.
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 400
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
// We use a flickable to synchronize the position of the editor and
|
||||
// the line numbers. This is necessary because the line numbers can
|
||||
// extend the available height.
|
||||
Flickable {
|
||||
id: lineNumbers
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: false
|
||||
// Calculating the width correctly is important as the number grows.
|
||||
// We need to ensure space required to show N line number digits.
|
||||
// We use log10 to find how many digits are needed in a line number.
|
||||
// log10(9) ~= .95; log10(10) = 1.0; log10(100) = 2.0 ...etc
|
||||
// We +1 to ensure space for at least 1 digit, as floor(1.95) = 1.
|
||||
// The +10 is additional spacing and can be adjusted.
|
||||
Layout.preferredWidth: fontMetrics.averageCharacterWidth * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10
|
||||
contentY: editorFlickable.contentY
|
||||
interactive: false
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
topPadding: textArea.topPadding
|
||||
|
||||
Repeater {
|
||||
id: repeatedLineNumbers
|
||||
// TODO: Bug where text wrapping shows as new line number.
|
||||
model: textArea.lineCount
|
||||
|
||||
// This Item is used for each line number in the gutter.
|
||||
delegate: Item {
|
||||
// Calculates the height of each line in the text area.
|
||||
height: textArea.contentHeight / textArea.lineCount
|
||||
width: parent.width
|
||||
|
||||
required property int index
|
||||
|
||||
// Show the line number.
|
||||
Label {
|
||||
id: numbers
|
||||
color: RustColors.linenumber
|
||||
font: textArea.font
|
||||
height: parent.height
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
text: parent.index + 1
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
width: parent.width - indicator.width
|
||||
}
|
||||
// Draw edge along the right side of the line number.
|
||||
Rectangle {
|
||||
id: indicator
|
||||
anchors.left: numbers.right
|
||||
color: RustColors.linenumber
|
||||
height: parent.height
|
||||
width: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Flickable {
|
||||
id: editorFlickable
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
height: 650
|
||||
|
||||
ScrollBar.horizontal: MyScrollBar {
|
||||
}
|
||||
ScrollBar.vertical: MyScrollBar {
|
||||
}
|
||||
|
||||
TextArea.flickable: TextArea {
|
||||
id: textArea
|
||||
focus: true
|
||||
persistentSelection: true
|
||||
antialiasing: true
|
||||
selectByMouse: true
|
||||
selectionColor: RustColors.editor_highlight
|
||||
selectedTextColor: RustColors.editor_highlighted_text
|
||||
textFormat: Qt.AutoText
|
||||
wrapMode: TextArea.Wrap
|
||||
text: FileSystem.readFile(root.filePath)
|
||||
|
||||
onLinkActivated: function (link) {
|
||||
Qt.openUrlExternally(link);
|
||||
}
|
||||
|
||||
// TODO: Handle saving
|
||||
// Component.onCompleted: {
|
||||
// if (Qt.application.arguments.length === 2)
|
||||
// textDocument.source = "file:" + Qt.application.arguments[1]
|
||||
// else
|
||||
// textDocument.source = "qrc:/texteditor.html"
|
||||
// }
|
||||
// textDocument.onStatusChanged: {
|
||||
// // a message lookup table using computed properties:
|
||||
// // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
|
||||
// const statusMessages = {
|
||||
// [ TextDocument.ReadError ]: qsTr("Failed to load “%1”"),
|
||||
// [ TextDocument.WriteError ]: qsTr("Failed to save “%1”"),
|
||||
// [ TextDocument.NonLocalFileError ]: qsTr("Not a local file: “%1”"),
|
||||
// }
|
||||
// const err = statusMessages[textDocument.status]
|
||||
// if (err) {
|
||||
// errorDialog.text = err.arg(textDocument.source)
|
||||
// errorDialog.open()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
FontMetrics {
|
||||
id: fontMetrics
|
||||
|
||||
font: textArea.font
|
||||
}
|
||||
}
|
||||
}
|
||||
TextArea {
|
||||
id: areaConsole
|
||||
|
||||
height: 100
|
||||
placeholderText: qsTr("Placeholder for bash terminal.")
|
||||
placeholderTextColor: "white"
|
||||
readOnly: true
|
||||
wrapMode: TextArea.Wrap
|
||||
background: Rectangle {
|
||||
color: RustColors.editor_background
|
||||
implicitHeight: 100
|
||||
// border.color: control.enabled ? RustColors.active : RustColors.inactive
|
||||
}
|
||||
}
|
||||
|
||||
// We use an inline component to customize the horizontal and vertical
|
||||
// scroll-bars. This is convenient when the component is only used in one file.
|
||||
component MyScrollBar: ScrollBar {
|
||||
id: scrollBar
|
||||
|
||||
// Scroll bar gutter
|
||||
background: Rectangle {
|
||||
implicitHeight: scrollBar.interactive ? 8 : 4
|
||||
implicitWidth: scrollBar.interactive ? 8 : 4
|
||||
color: RustColors.scrollbar_gutter
|
||||
|
||||
// Fade the scrollbar gutter when inactive.
|
||||
opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.2
|
||||
Behavior on opacity {
|
||||
OpacityAnimator {
|
||||
duration: 500
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll bar
|
||||
contentItem: Rectangle {
|
||||
implicitHeight: scrollBar.interactive ? 8 : 4
|
||||
implicitWidth: scrollBar.interactive ? 8 : 4
|
||||
|
||||
// If we don't need a scrollbar, fallback to the gutter color.
|
||||
// If the scrollbar is required change it's color based on activity.
|
||||
color: scrollBar.size < 1.0 ? scrollBar.active ? RustColors.scrollbar_active : RustColors.scrollbar : RustColors.scrollbar_gutter
|
||||
// Smooth transition between color changes based on the state above.
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 1000
|
||||
}
|
||||
}
|
||||
// Fade the scrollbar when inactive.
|
||||
opacity: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.35
|
||||
Behavior on opacity {
|
||||
OpacityAnimator {
|
||||
duration: 500
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,42 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import clide.module 1.0
|
||||
|
||||
MenuBar {
|
||||
background: Rectangle {
|
||||
color: "#3b3e40" // Dark background like CLion
|
||||
// Base settings for each Menu.
|
||||
component ClideMenu : Menu {
|
||||
background: Rectangle {
|
||||
color: RustColors.menubar
|
||||
implicitWidth: 100
|
||||
radius: 2
|
||||
}
|
||||
}
|
||||
|
||||
// Base settings for each MenuItem.
|
||||
component ClideMenuItem : MenuItem {
|
||||
id: root
|
||||
|
||||
background: Rectangle {
|
||||
color: root.hovered ? RustColors.hovered : RustColors.unhovered
|
||||
radius: 2.5
|
||||
}
|
||||
contentItem: IconLabel {
|
||||
color: "black"
|
||||
font.family: "Helvetica"
|
||||
text: root.text
|
||||
}
|
||||
}
|
||||
|
||||
// Background for this MenuBar.
|
||||
background: Rectangle {
|
||||
color: RustColors.menubar
|
||||
border.color: RustColors.menubar_border
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// File Menu
|
||||
Action {
|
||||
id: actionNewProject
|
||||
|
||||
@ -25,32 +56,37 @@ MenuBar {
|
||||
id: actionExit
|
||||
|
||||
text: qsTr("&Exit")
|
||||
|
||||
onTriggered: Qt.quit()
|
||||
}
|
||||
ClideMenu {
|
||||
title: qsTr("&File")
|
||||
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionNewProject
|
||||
}
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionOpen
|
||||
onTriggered: FileSystem.setDirectory(FileSystem.filePath)
|
||||
}
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionSave
|
||||
}
|
||||
MenuSeparator {
|
||||
background: Rectangle {
|
||||
border.color: color
|
||||
color: "#3c3f41"
|
||||
color: RustColors.menubar_border
|
||||
implicitHeight: 3
|
||||
implicitWidth: 200
|
||||
}
|
||||
}
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionExit
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Edit Menu
|
||||
Action {
|
||||
id: actionUndo
|
||||
|
||||
@ -79,22 +115,25 @@ MenuBar {
|
||||
ClideMenu {
|
||||
title: qsTr("&Edit")
|
||||
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionUndo
|
||||
}
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionRedo
|
||||
}
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionCut
|
||||
}
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionCopy
|
||||
}
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionPaste
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// View Menu
|
||||
Action {
|
||||
id: actionToolWindows
|
||||
|
||||
@ -108,13 +147,20 @@ MenuBar {
|
||||
ClideMenu {
|
||||
title: qsTr("&View")
|
||||
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionToolWindows
|
||||
}
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionAppearance
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Help Menu
|
||||
ClideAboutWindow {
|
||||
id: clideAbout
|
||||
}
|
||||
|
||||
Action {
|
||||
id: actionDocumentation
|
||||
|
||||
@ -122,16 +168,18 @@ MenuBar {
|
||||
}
|
||||
Action {
|
||||
id: actionAbout
|
||||
// Toggle the about window with the menu item is clicked.
|
||||
onTriggered: clideAbout.visible = !clideAbout.visible
|
||||
|
||||
text: qsTr("&About")
|
||||
}
|
||||
ClideMenu {
|
||||
title: qsTr("&Help")
|
||||
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionDocumentation
|
||||
}
|
||||
ClideMenuBarItem {
|
||||
ClideMenuItem {
|
||||
action: actionAbout
|
||||
}
|
||||
}
|
||||
55
qml/ClideProjectView.qml
Normal file
55
qml/ClideProjectView.qml
Normal file
@ -0,0 +1,55 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import clide.module 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
|
||||
// Path to the file selected in the tree view.
|
||||
default property string selectedFilePath: FileSystem.filePath;
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
anchors.fill: parent
|
||||
|
||||
// Customized handle to drag between the Navigation and the Editor.
|
||||
handle: Rectangle {
|
||||
id: verticalSplitHandle
|
||||
border.color: SplitHandle.pressed ? RustColors.pressed : SplitHandle.hovered ? RustColors.hovered : RustColors.gutter
|
||||
color: SplitHandle.pressed ? RustColors.pressed : SplitHandle.hovered ? RustColors.hovered : RustColors.gutter
|
||||
implicitWidth: 8
|
||||
radius: 2.5
|
||||
|
||||
// Execute these behaviors when the color is changed.
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 400
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: navigationView
|
||||
color: RustColors.explorer_background
|
||||
|
||||
SplitView.fillHeight: true
|
||||
SplitView.minimumWidth: 0
|
||||
SplitView.preferredWidth: 200
|
||||
SplitView.maximumWidth: 250
|
||||
|
||||
StackLayout {
|
||||
anchors.fill: parent
|
||||
ClideTreeView {
|
||||
id: clideTreeView
|
||||
onFileClicked: path => root.selectedFilePath = path
|
||||
}
|
||||
}
|
||||
}
|
||||
ClideEditor {
|
||||
SplitView.fillWidth: true
|
||||
// Initialize using the Default trait in Rust QML singleton FileSystem.
|
||||
filePath: root.selectedFilePath
|
||||
}
|
||||
}
|
||||
146
qml/ClideTreeView.qml
Normal file
146
qml/ClideTreeView.qml
Normal file
@ -0,0 +1,146 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import clide.module 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: RustColors.explorer_background
|
||||
|
||||
signal fileClicked(string filePath)
|
||||
|
||||
TreeView {
|
||||
id: fileSystemTreeView
|
||||
anchors.margins: 15
|
||||
|
||||
// rootIndex: FileSystem.rootIndex
|
||||
property int lastIndex: -1
|
||||
|
||||
model: FileSystem
|
||||
anchors.fill: parent
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
boundsMovement: Flickable.StopAtBounds
|
||||
clip: true
|
||||
|
||||
Component.onCompleted: {
|
||||
FileSystem.setDirectory(FileSystem.filePath)
|
||||
fileSystemTreeView.expandRecursively(0, 4)
|
||||
}
|
||||
|
||||
// The delegate represents a single entry in the filesystem.
|
||||
delegate: TreeViewDelegate {
|
||||
id: treeDelegate
|
||||
indentation: 8
|
||||
implicitWidth: fileSystemTreeView.width > 0 ? fileSystemTreeView.width : 250
|
||||
implicitHeight: 25
|
||||
|
||||
required property int index
|
||||
required property url filePath
|
||||
required property string fileName
|
||||
|
||||
indicator: Image {
|
||||
id: directoryIcon
|
||||
|
||||
x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: {
|
||||
// If the item has children, it's a directory.
|
||||
if (treeDelegate.hasChildren) {
|
||||
return treeDelegate.expanded ?
|
||||
"../icons/folder-open-solid.svg" : "../icons/folder-solid.svg";
|
||||
}
|
||||
return "../icons/file-solid.svg"
|
||||
}
|
||||
sourceSize.width: 15
|
||||
sourceSize.height: 15
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
smooth: true
|
||||
antialiasing: true
|
||||
asynchronous: true
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
text: treeDelegate.fileName
|
||||
color: RustColors.explorer_text
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
// TODO: Fix flickering from color transition on states here.
|
||||
color: (treeDelegate.index === fileSystemTreeView.lastIndex)
|
||||
? RustColors.explorer_text_selected
|
||||
: (hoverHandler.hovered ? RustColors.explorer_hovered : "transparent")
|
||||
radius: 2.5
|
||||
opacity: hoverHandler.hovered ? 0.75 : 1.0
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onSingleTapped: (eventPoint, button) => {
|
||||
switch (button) {
|
||||
case Qt.LeftButton:
|
||||
fileSystemTreeView.toggleExpanded(treeDelegate.row)
|
||||
fileSystemTreeView.lastIndex = treeDelegate.index
|
||||
// If this model item doesn't have children, it means it's
|
||||
// representing a file.
|
||||
if (!treeDelegate.hasChildren)
|
||||
root.fileClicked(treeDelegate.filePath)
|
||||
break;
|
||||
case Qt.RightButton:
|
||||
if (treeDelegate.hasChildren)
|
||||
contextMenu.popup();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
id: contextMenu
|
||||
Action {
|
||||
text: qsTr("Set as root index")
|
||||
onTriggered: {
|
||||
console.log("Setting directory: " + treeDelegate.filePath)
|
||||
FileSystem.setDirectory(treeDelegate.filePath)
|
||||
}
|
||||
}
|
||||
Action {
|
||||
text: qsTr("Reset root index")
|
||||
onTriggered: {
|
||||
FileSystem.setDirectory("")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Provide our own custom ScrollIndicator for the TreeView.
|
||||
ScrollIndicator.vertical: ScrollIndicator {
|
||||
active: true
|
||||
implicitWidth: 15
|
||||
|
||||
contentItem: Rectangle {
|
||||
implicitWidth: 6
|
||||
implicitHeight: 6
|
||||
|
||||
color: RustColors.scrollbar
|
||||
opacity: fileSystemTreeView.movingVertically ? 0.5 : 0.0
|
||||
|
||||
Behavior on opacity {
|
||||
OpacityAnimator {
|
||||
duration: 500
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
Menu {
|
||||
background: Rectangle {
|
||||
color: "#3c3f41"
|
||||
implicitWidth: 200
|
||||
radius: 2
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
MenuItem {
|
||||
id: root
|
||||
|
||||
background: Rectangle {
|
||||
color: root.hovered ? "#4b4f51" : "#3c3f41" // Hover effect
|
||||
radius: 2.5
|
||||
}
|
||||
contentItem: IconLabel {
|
||||
color: "white"
|
||||
font.family: "Helvetica"
|
||||
text: root.text
|
||||
}
|
||||
}
|
||||
15
qml/main.qml
15
qml/main.qml
@ -1,10 +1,13 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import "Menu"
|
||||
import clide.module 1.0
|
||||
|
||||
ApplicationWindow {
|
||||
id: appWindow
|
||||
|
||||
height: 800
|
||||
title: "CLIDE"
|
||||
visible: true
|
||||
@ -15,6 +18,14 @@ ApplicationWindow {
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "#1e1f22" // Dark background
|
||||
color: RustColors.gutter
|
||||
}
|
||||
|
||||
MessageDialog {
|
||||
id: errorDialog
|
||||
|
||||
title: qsTr("Error")
|
||||
}
|
||||
ClideProjectView {
|
||||
}
|
||||
}
|
||||
|
||||
38
src/gui.rs
Normal file
38
src/gui.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use crate::gui::filesystem::FS_STATE;
|
||||
use crate::gui::filesystem::qobject::FileSystem;
|
||||
use cxx_qt_lib::{QModelIndex, QQmlEngine, QString};
|
||||
use std::error::Error;
|
||||
|
||||
pub mod colors;
|
||||
pub mod filesystem;
|
||||
|
||||
pub fn run(root_path: std::path::PathBuf) -> Result<(), Box<dyn Error>> {
|
||||
println!("Starting the GUI editor at {:?}", root_path);
|
||||
|
||||
use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl};
|
||||
|
||||
let mut app = QGuiApplication::new();
|
||||
let mut engine = QQmlApplicationEngine::new();
|
||||
|
||||
// let clide_fs = FileSystemImpl {
|
||||
// file_path: QString::from(root_path.to_str().unwrap()),
|
||||
// root_index: QModelIndex::default(),
|
||||
// };
|
||||
unsafe {
|
||||
let mut fs_state = FS_STATE.take_fs();
|
||||
fs_state.file_path = QString::from(root_path.to_str().unwrap());
|
||||
};
|
||||
|
||||
if let Some(engine) = engine.as_mut() {
|
||||
engine.add_import_path(&QString::from("qml/"));
|
||||
}
|
||||
if let Some(engine) = engine.as_mut() {
|
||||
engine.load(&QUrl::from("qml/main.qml"));
|
||||
}
|
||||
|
||||
if let Some(app) = app.as_mut() {
|
||||
app.exec();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
92
src/gui/colors.rs
Normal file
92
src/gui/colors.rs
Normal file
@ -0,0 +1,92 @@
|
||||
#[cxx_qt::bridge]
|
||||
pub mod qobject {
|
||||
unsafe extern "C++" {
|
||||
include!("cxx-qt-lib/qcolor.h");
|
||||
type QColor = cxx_qt_lib::QColor;
|
||||
}
|
||||
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[qml_element]
|
||||
#[qml_singleton]
|
||||
#[qproperty(QColor, hovered)]
|
||||
#[qproperty(QColor, unhovered)]
|
||||
#[qproperty(QColor, pressed)]
|
||||
#[qproperty(QColor, menubar)]
|
||||
#[qproperty(QColor, menubar_border)]
|
||||
#[qproperty(QColor, scrollbar)]
|
||||
#[qproperty(QColor, scrollbar_active)]
|
||||
#[qproperty(QColor, scrollbar_gutter)]
|
||||
#[qproperty(QColor, linenumber)]
|
||||
#[qproperty(QColor, active)]
|
||||
#[qproperty(QColor, inactive)]
|
||||
#[qproperty(QColor, editor_background)]
|
||||
#[qproperty(QColor, editor_text)]
|
||||
#[qproperty(QColor, editor_highlighted_text)]
|
||||
#[qproperty(QColor, editor_highlight)]
|
||||
#[qproperty(QColor, gutter)]
|
||||
#[qproperty(QColor, explorer_hovered)]
|
||||
#[qproperty(QColor, explorer_text)]
|
||||
#[qproperty(QColor, explorer_text_selected)]
|
||||
#[qproperty(QColor, explorer_background)]
|
||||
#[qproperty(QColor, explorer_folder)]
|
||||
#[qproperty(QColor, explorer_folder_open)]
|
||||
type RustColors = super::RustColorsImpl;
|
||||
}
|
||||
}
|
||||
|
||||
use cxx_qt_lib::QColor;
|
||||
|
||||
pub struct RustColorsImpl {
|
||||
hovered: QColor,
|
||||
unhovered: QColor,
|
||||
pressed: QColor,
|
||||
menubar: QColor,
|
||||
menubar_border: QColor,
|
||||
scrollbar: QColor,
|
||||
scrollbar_active: QColor,
|
||||
scrollbar_gutter: QColor,
|
||||
linenumber: QColor,
|
||||
active: QColor,
|
||||
inactive: QColor,
|
||||
editor_background: QColor,
|
||||
editor_text: QColor,
|
||||
editor_highlighted_text: QColor,
|
||||
editor_highlight: QColor,
|
||||
gutter: QColor,
|
||||
explorer_hovered: QColor,
|
||||
explorer_text: QColor,
|
||||
explorer_text_selected: QColor,
|
||||
explorer_background: QColor,
|
||||
explorer_folder: QColor,
|
||||
explorer_folder_open: QColor,
|
||||
}
|
||||
|
||||
impl Default for RustColorsImpl {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
hovered: QColor::try_from("#303234").unwrap(),
|
||||
unhovered: QColor::try_from("#3c3f41").unwrap(),
|
||||
pressed: QColor::try_from("#4b4f51").unwrap(),
|
||||
menubar: QColor::try_from("#3c3f41").unwrap(),
|
||||
menubar_border: QColor::try_from("#575757").unwrap(),
|
||||
scrollbar: QColor::try_from("#4b4f51").unwrap(),
|
||||
scrollbar_active: QColor::try_from("#4b4f51").unwrap(),
|
||||
scrollbar_gutter: QColor::try_from("#3b3b3b").unwrap(),
|
||||
linenumber: QColor::try_from("#94989b").unwrap(),
|
||||
active: QColor::try_from("#a9acb0").unwrap(),
|
||||
inactive: QColor::try_from("#FFF").unwrap(),
|
||||
editor_background: QColor::try_from("#2b2b2b").unwrap(),
|
||||
editor_text: QColor::try_from("#acaea3").unwrap(),
|
||||
editor_highlighted_text: QColor::try_from("#ccced3").unwrap(),
|
||||
editor_highlight: QColor::try_from("#ccced3").unwrap(),
|
||||
gutter: QColor::try_from("#1e1f22").unwrap(),
|
||||
explorer_hovered: QColor::try_from("#4c5053").unwrap(),
|
||||
explorer_text: QColor::try_from("#3b3b3b").unwrap(),
|
||||
explorer_text_selected: QColor::try_from("#8b8b8b").unwrap(),
|
||||
explorer_background: QColor::try_from("#676c70").unwrap(),
|
||||
explorer_folder: QColor::try_from("#54585b").unwrap(),
|
||||
explorer_folder_open: QColor::try_from("#FFF").unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
153
src/gui/filesystem.rs
Normal file
153
src/gui/filesystem.rs
Normal file
@ -0,0 +1,153 @@
|
||||
#[cxx_qt::bridge]
|
||||
pub mod qobject {
|
||||
unsafe extern "C++" {
|
||||
// Import Qt Types from C++
|
||||
include!("cxx-qt-lib/qstring.h");
|
||||
type QString = cxx_qt_lib::QString;
|
||||
include!("cxx-qt-lib/qmodelindex.h");
|
||||
type QModelIndex = cxx_qt_lib::QModelIndex;
|
||||
include!(<QtGui/QFileSystemModel>);
|
||||
type QFileSystemModel;
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
// Export QML Types from Rust
|
||||
#[qobject]
|
||||
#[base = QFileSystemModel]
|
||||
#[qml_element]
|
||||
#[qml_singleton]
|
||||
#[qproperty(QString, file_path]
|
||||
#[qproperty(QModelIndex, root_index]
|
||||
type FileSystem = super::FileSystemImpl;
|
||||
|
||||
#[inherit]
|
||||
fn set_root_path(self: Pin<&mut FileSystem>, path: &QString) -> QModelIndex;
|
||||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
fn column_count(self: &FileSystem, _index: &QModelIndex) -> i32;
|
||||
|
||||
#[qinvokable]
|
||||
fn read_file(self: &FileSystem, path: &QString) -> QString;
|
||||
|
||||
#[qinvokable]
|
||||
fn set_directory(self: Pin<&mut FileSystem>, path: &QString) -> QModelIndex;
|
||||
|
||||
#[qinvokable]
|
||||
fn take_fs(self: &mut) -> FileSystem;
|
||||
}
|
||||
}
|
||||
|
||||
use cxx_qt_lib::{QModelIndex, QString};
|
||||
use dirs;
|
||||
use log::warn;
|
||||
use std::fs;
|
||||
use std::io::BufRead;
|
||||
use std::ptr::replace;
|
||||
use syntect::easy::HighlightFile;
|
||||
use syntect::highlighting::ThemeSet;
|
||||
use syntect::html::{
|
||||
IncludeBackground, append_highlighted_html_for_styled_line, start_highlighted_html_snippet,
|
||||
};
|
||||
use syntect::parsing::SyntaxSet;
|
||||
|
||||
/// Singleton holding filesystem state.
|
||||
pub struct FileSystemState {
|
||||
pub fs: Option<FileSystemImpl>,
|
||||
}
|
||||
|
||||
impl FileSystemState {
|
||||
pub unsafe fn take_fs(&mut self) -> FileSystemImpl {
|
||||
let fs = replace(&mut self.fs, None);
|
||||
fs.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub static mut FS_STATE : FileSystemState = FileSystemState { fs: Some(FileSystemImpl::default()) };
|
||||
|
||||
// TODO: Implement a provider for QFileSystemModel::setIconProvider for icons.
|
||||
pub struct FileSystemImpl {
|
||||
pub file_path: QString,
|
||||
pub root_index: QModelIndex,
|
||||
}
|
||||
|
||||
// Default is explicit to make the editor open this source file initially.
|
||||
impl Default for FileSystemImpl {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
file_path: QString::from(file!()),
|
||||
root_index: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl qobject::FileSystem {
|
||||
fn read_file(&self, path: &QString) -> QString {
|
||||
if path.is_empty() {
|
||||
return QString::default();
|
||||
}
|
||||
if !fs::metadata(path.to_string())
|
||||
.expect(format!("Failed to get file metadata {}", path).as_str())
|
||||
.is_file()
|
||||
{
|
||||
warn!("Attempted to open file {} that is not a valid file", path);
|
||||
return QString::default();
|
||||
}
|
||||
let ss = SyntaxSet::load_defaults_nonewlines();
|
||||
let ts = ThemeSet::load_defaults();
|
||||
let theme = &ts.themes["base16-ocean.dark"];
|
||||
|
||||
let mut highlighter =
|
||||
HighlightFile::new(path.to_string(), &ss, theme).expect("Failed to create highlighter");
|
||||
let (mut output, _bg) = start_highlighted_html_snippet(theme);
|
||||
let mut line = String::new();
|
||||
while highlighter
|
||||
.reader
|
||||
.read_line(&mut line)
|
||||
.expect("Failed to read file.")
|
||||
> 0
|
||||
{
|
||||
let regions = highlighter
|
||||
.highlight_lines
|
||||
.highlight_line(&line, &ss)
|
||||
.expect("Failed to highlight");
|
||||
|
||||
append_highlighted_html_for_styled_line(
|
||||
®ions[..],
|
||||
IncludeBackground::Yes,
|
||||
&mut output,
|
||||
)
|
||||
.expect("Failed to insert highlighted html");
|
||||
line.clear();
|
||||
}
|
||||
output.push_str("</pre>\n");
|
||||
QString::from(output)
|
||||
}
|
||||
|
||||
// There will never be more than one column.
|
||||
fn column_count(&self, _index: &QModelIndex) -> i32 {
|
||||
1
|
||||
}
|
||||
|
||||
fn set_directory(self: std::pin::Pin<&mut Self>, path: &QString) -> QModelIndex {
|
||||
if !path.is_empty()
|
||||
&& fs::metadata(path.to_string())
|
||||
.expect(format!("Failed to get metadata for path {}", path).as_str())
|
||||
.is_dir()
|
||||
{
|
||||
self.set_root_path(path)
|
||||
} else {
|
||||
// If the initial directory can't be opened, attempt to find the home directory.
|
||||
self.set_root_path(&QString::from(
|
||||
dirs::home_dir()
|
||||
.expect("Failed to get home directory")
|
||||
.as_path()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
128
src/main.rs
128
src/main.rs
@ -1,90 +1,58 @@
|
||||
// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
// SPDX-FileContributor: Leon Matthes <leon.matthes@kdab.com>
|
||||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
// TODO: Header
|
||||
|
||||
#[cxx_qt::bridge]
|
||||
mod qobject {
|
||||
unsafe extern "C++" {
|
||||
include!("cxx-qt-lib/qstring.h");
|
||||
type QString = cxx_qt_lib::QString;
|
||||
}
|
||||
use std::error::Error;
|
||||
use std::process::{Command, Stdio};
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[qenum(Greeter)]
|
||||
pub enum Language {
|
||||
English,
|
||||
German,
|
||||
French,
|
||||
}
|
||||
pub mod gui;
|
||||
pub mod tui;
|
||||
|
||||
#[qenum(Greeter)]
|
||||
pub enum Greeting {
|
||||
Hello,
|
||||
Bye,
|
||||
}
|
||||
/// Command line interface IDE with full GUI and headless modes.
|
||||
/// If no flags are provided the GUI editor is launched in a separate process.
|
||||
/// If no path is provided the current directory is used.
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(name = "clide", verbatim_doc_comment)]
|
||||
struct Cli {
|
||||
/// The root directory for the project to open with the clide editor.
|
||||
#[structopt(parse(from_os_str))]
|
||||
pub path: Option<std::path::PathBuf>,
|
||||
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[qml_element]
|
||||
#[qproperty(Greeting, greeting)]
|
||||
#[qproperty(Language, language)]
|
||||
type Greeter = super::GreeterRust;
|
||||
/// Run clide in headless mode.
|
||||
#[structopt(name = "tui", short, long)]
|
||||
pub tui: bool,
|
||||
|
||||
#[qinvokable]
|
||||
fn greet(self: &Greeter) -> QString;
|
||||
}
|
||||
/// Run the clide GUI in the current process, blocking the terminal and showing all output streams.
|
||||
#[structopt(name = "gui", short, long)]
|
||||
pub gui: bool,
|
||||
}
|
||||
|
||||
use qobject::*;
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args = Cli::from_args();
|
||||
|
||||
impl Greeting {
|
||||
fn translate(&self, language: Language) -> String {
|
||||
match (self, language) {
|
||||
(&Greeting::Hello, Language::English) => "Hello, World!",
|
||||
(&Greeting::Hello, Language::German) => "Hallo, Welt!",
|
||||
(&Greeting::Hello, Language::French) => "Bonjour, le monde!",
|
||||
(&Greeting::Bye, Language::English) => "Bye!",
|
||||
(&Greeting::Bye, Language::German) => "Auf Wiedersehen!",
|
||||
(&Greeting::Bye, Language::French) => "Au revoir!",
|
||||
_ => "🤯",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GreeterRust {
|
||||
greeting: Greeting,
|
||||
language: Language,
|
||||
}
|
||||
|
||||
impl Default for GreeterRust {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
greeting: Greeting::Hello,
|
||||
language: Language::English,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use cxx_qt_lib::QString;
|
||||
|
||||
impl qobject::Greeter {
|
||||
fn greet(&self) -> QString {
|
||||
QString::from(self.greeting.translate(self.language))
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl};
|
||||
|
||||
let mut app = QGuiApplication::new();
|
||||
let mut engine = QQmlApplicationEngine::new();
|
||||
|
||||
if let Some(engine) = engine.as_mut() {
|
||||
engine.load(&QUrl::from("qml/main.qml"));
|
||||
}
|
||||
|
||||
if let Some(app) = app.as_mut() {
|
||||
app.exec();
|
||||
let root_path = match args.path {
|
||||
// If the CLI was provided a directory convert it to absolute.
|
||||
Some(path) => std::path::absolute(path)?,
|
||||
// If no path was provided, use current directory.
|
||||
None => std::env::current_dir().unwrap_or_else(|_|
|
||||
// If we can't find the CWD attempt to open the home directory.
|
||||
dirs::home_dir().expect("Failed to access filesystem.")),
|
||||
};
|
||||
|
||||
match args.gui {
|
||||
true => gui::run(root_path),
|
||||
false => match args.tui {
|
||||
// Open the TUI editor if requested, otherwise use the QML GUI by default.
|
||||
true => tui::run(root_path),
|
||||
false => {
|
||||
// Relaunch the CLIDE GUI in a separate process.
|
||||
Command::new(std::env::current_exe()?)
|
||||
.args(&["--gui", root_path.to_str().unwrap()])
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.stdin(Stdio::null())
|
||||
.spawn()?;
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
6
src/tui.rs
Normal file
6
src/tui.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use std::error::Error;
|
||||
|
||||
pub fn run(root_path: std::path::PathBuf) -> Result<(), Box<dyn Error>> {
|
||||
println!("Starting the TUI editor at {:?}", root_path);
|
||||
Ok(())
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user