Dispaly caret, unify text character render

This commit is contained in:
Adrian Wozniak 2019-01-03 10:38:54 +01:00
parent 399b0b7144
commit 85014a2af2
No known key found for this signature in database
GPG Key ID: 3B441F7808FC43C7
19 changed files with 1114 additions and 271 deletions

219
Cargo.lock generated
View File

@ -1,3 +1,47 @@
[[package]]
name = "argon2rs"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "arrayvec"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "autocfg"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "backtrace"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bit-set"
version = "0.4.0"
@ -21,11 +65,25 @@ name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "blake2-rfc"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "c_vec"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.6"
@ -39,13 +97,52 @@ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "constant_time_eq"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "dirs"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "editor"
version = "0.1.0"
dependencies = [
"dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"plex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure_derive"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -62,6 +159,11 @@ name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "itoa"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lalr"
version = "0.0.2"
@ -74,7 +176,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.44"
version = "0.2.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nodrop"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -143,7 +250,7 @@ version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -153,7 +260,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -164,7 +271,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -191,6 +298,37 @@ dependencies = [
"vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_users"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ryu"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "sdl2"
version = "0.31.0"
@ -199,7 +337,7 @@ dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"c_vec 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -213,6 +351,31 @@ dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde"
version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.14.9"
@ -223,6 +386,27 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synstructure"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-xid"
version = "0.1.0"
@ -253,18 +437,31 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e5f34df7a019573fb8bdc7e24a2bfebe51a2a1d6bfdbaeccedb3c41fc574727"
"checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5"
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
"checksum c_vec 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6c32b15e95ce816aaf991a41420854e6ba772a2679a9296d906eab1114f1b4e9"
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
"checksum lalr 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "106d7548f95adbe3019b4fc4954554d7b72535867aa9ce326d2f766b68958de7"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
@ -278,9 +475,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
"checksum redfa 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "29cc2771cc9f5fb0061cdedc05a37170254694dffec6b89920a6e767f08c4220"
"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
"checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26"
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60"
"checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7"
"checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7"
"checksum serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d6115a3ca25c224e409185325afc16a0d5aaaabc15c42b09587d6f1ba39a5b"
"checksum serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "bdf540260cfee6da923831f4776ddc495ada940c30117977c70f1313a6130545"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"

View File

@ -7,6 +7,10 @@ edition = "2018"
[dependencies]
rand = "0.5"
plex = "*"
dirs = "*"
serde = "*"
serde_json = "*"
serde_derive = "*"
[dependencies.sdl2]
version = "0.31.0"

56
assets/theme.txt Normal file
View File

@ -0,0 +1,56 @@
```railscasts
``comment
#BC9358
italic
``escaped character
#509E4F
``class
#FFF
``constant
#FFF
``float
#A4C260
``function
#FFC56D
``global variable
#D0CFFE
``integer
#A4C260
``inline code
#151515
``instance variable
#D0CFFE
``doctype
#E7BE69
``keyword
#CB7832
``keyword
#CB7832
``regex
#A4C260
``string
#A4C260
``symbol
#6C9CBD
``html tag
#E7BE69
``boolean
#6C9CBD

View File

@ -2,43 +2,54 @@ use std::rc::Rc;
use std::sync::Arc;
use std::boxed::Box;
use crate::app::{UpdateResult, WindowCanvas};
use crate::ui::*;
use crate::ui::caret::Caret;
use crate::file::*;
use crate::renderer::Renderer;
use crate::file::editor_file::EditorFile;
use crate::renderer::Renderer;
pub struct AppState<'a> {
pub files: Vec<EditorFile<'a>>,
pub struct AppState {
pub files: Vec<EditorFile>,
pub current_file: i16,
caret: Caret,
}
impl<'a> AppState<'a> {
impl AppState {
pub fn new() -> Self {
Self {
files: vec![],
current_file: -1,
caret: Caret::new(),
}
}
pub fn open_file(&mut self, file_path: String, renderer: &mut Renderer) {
pub fn open_file(&mut self, file_path: String) {
use std::fs::read_to_string;
if let Ok(buffer) = read_to_string(&file_path) {
println!("read: {}\n{}", file_path, buffer);
let file = EditorFile::new(file_path.clone(), buffer, renderer);
let file = EditorFile::new(file_path.clone(), buffer);
self.current_file = self.files.len() as i16;
self.files.push(file);
};
}
}
pub fn update(&mut self, ticks: i32) -> UpdateResult {
if let Some(ref mut file) = self.files.get(self.current_file as usize) {
file.update(ticks);
}
UpdateResult::NoOp
}
pub fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) {
if let Some(ref mut file) = self.files.get(self.current_file as usize) {
impl Render for AppState {
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
if let Some(file) = self.files.get_mut(self.current_file as usize) {
file.render(canvas, renderer);
}
self.caret.render(canvas, renderer);
UpdateResult::NoOp
}
}
impl Update for AppState {
fn update(&mut self, ticks: i32) -> UpdateResult {
if let Some(file) = self.files.get_mut(self.current_file as usize) {
file.update(ticks);
}
self.caret.update(ticks);
UpdateResult::NoOp
}
}

View File

@ -1,3 +1,5 @@
use crate::themes::Theme;
#[derive(Debug, Clone)]
pub struct EditorConfig {
pub character_size: u16,
@ -9,6 +11,7 @@ pub struct Config {
pub width: u32,
pub height: u32,
pub editor_config: EditorConfig,
pub theme: Theme,
}
impl Config {
@ -20,6 +23,7 @@ impl Config {
character_size: 24,
font_path: "./assets/fonts/hinted-ElaineSans-Medium.ttf".to_string(),
},
theme: Theme::load("default".to_string()),
}
}
}

View File

@ -16,6 +16,8 @@ pub type WindowCanvas = Canvas<Window>;
use crate::app::app_state::AppState;
use crate::app::config::Config;
use crate::themes::Theme;
use crate::ui::*;
use crate::renderer::Renderer;
#[derive(PartialEq, Clone, Debug)]
@ -71,12 +73,13 @@ impl Application {
let mut timer: TimerSubsystem = self.sdl_context.timer().unwrap();
let mut event_pump = self.sdl_context.event_pump().unwrap();
let font_context = sdl2::ttf::init().unwrap();
let texture_creator = self.canvas.texture_creator();
let sleep_time = Duration::new(0, 1_000_000_000u32 / 60);
let mut app_state = AppState::new();
let mut renderer = Renderer::new(
self.config.clone(),
&font_context,
self.canvas.texture_creator()
&texture_creator
);
'running: loop {
@ -89,14 +92,7 @@ impl Application {
match task {
Task::OpenFile { file_path } => {
use crate::file::editor_file::*;
app_state.open_file(file_path.clone(), &mut renderer);
// use std::fs::read_to_string;
// if let Ok(buffer) = read_to_string(&file_path) {
// println!("read: {}\n{}", file_path, buffer);
// let file = EditorFile::new(file_path.clone(), buffer, &mut renderer);
// app_state.current_file = app_state.files.len() as i16;
// app_state.files.push(file);
// }
app_state.open_file(file_path.clone());
},
}
}

View File

@ -1,19 +0,0 @@
pub struct Caret<'a> {
character: char,
source: Rect,
dest: Rect,
visible: bool,
texture: Option<Rc<Texture<'a>>>,
}
impl<'a> Caret<'a> {
pub fn new() -> Self {
Self {
character: '',
source: Rect::new(0, 0, 0, 0),
dest: Rect::new(0, 0, 0, 0),
visible: true,
texture: None,
}
}
}

View File

@ -1,41 +1,22 @@
use sdl2::rect::Rect;
use crate::file::editor_file_section::EditorFileSection;
use crate::renderer::Renderer;
use crate::app::UpdateResult;
use crate::app::WindowCanvas;
use crate::app::{UpdateResult, WindowCanvas};
use crate::ui::*;
#[derive(Clone)]
pub struct EditorFile<'l> {
pub struct EditorFile {
pub path: String,
pub sections: Vec<EditorFileSection<'l>>,
pub sections: Vec<EditorFileSection>,
}
impl<'l> EditorFile<'l> {
pub fn new(path: String, buffer: String, renderer: &'l mut Renderer) -> Self {
let section = EditorFileSection::new(buffer, renderer);
impl EditorFile {
pub fn new(path: String, buffer: String) -> Self {
let section = EditorFileSection::new(buffer);
let sections = vec![section];
Self { path, sections }
}
pub fn update(&mut self, ticks: i32) -> UpdateResult {
let mut result = UpdateResult::NoOp;
for section in self.sections.iter_mut() {
result = section.update(ticks);
}
if result == UpdateResult::RefreshPositions {
self.refresh_characters_position();
result = UpdateResult::NoOp;
}
result
}
pub fn render(&self, canvas: &mut WindowCanvas, renderer: &mut Renderer) {
for ref section in self.sections.iter() {
section.render(canvas, renderer);
}
}
fn refresh_characters_position(&mut self) {
let mut current: Rect = Rect::new(0, 0, 0, 0);
for section in self.sections.iter_mut() {
@ -43,3 +24,29 @@ impl<'l> EditorFile<'l> {
}
}
}
impl Render for EditorFile {
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
let mut res = UpdateResult::NoOp;
for section in self.sections.iter_mut() {
res = section.render(canvas, renderer);
}
if res == UpdateResult::RefreshPositions {
self.refresh_characters_position();
for section in self.sections.iter_mut() {
section.render(canvas, renderer);
}
}
UpdateResult::NoOp
}
}
impl Update for EditorFile {
fn update(&mut self, ticks: i32) -> UpdateResult {
let mut result = UpdateResult::NoOp;
for section in self.sections.iter_mut() {
result = section.update(ticks);
}
result
}
}

View File

@ -4,48 +4,54 @@ use crate::app::UpdateResult;
use crate::app::WindowCanvas;
use crate::renderer::Renderer;
use crate::file::editor_file_token::EditorFileToken;
use crate::ui::*;
#[derive(Clone)]
pub struct EditorFileSection<'l> {
pub tokens: Vec<EditorFileToken<'l>>,
pub struct EditorFileSection {
pub tokens: Vec<EditorFileToken>,
pub language: Language,
}
impl<'l> EditorFileSection<'l> {
pub fn new(buffer: String, renderer: &'l mut Renderer) -> Self {
impl EditorFileSection {
pub fn new(buffer: String) -> Self {
use crate::lexer;
let lexer_tokens = lexer::parse(buffer.clone(), Language::PlainText);
let mut tokens: Vec<EditorFileToken> = vec![];
for token_type in lexer_tokens {
let token = EditorFileToken::new(
renderer,
token_type.get_start(),
token_type.clone(),
);
let token = EditorFileToken::new(token_type);
tokens.push(token.clone());
}
let language = Language::PlainText;
Self { tokens, language }
}
pub fn update(&mut self, ticks: i32) -> UpdateResult {
let mut result = UpdateResult::NoOp;
for file_char in self.tokens.iter_mut() {
result = file_char.update(ticks)
}
result
}
pub fn render(&self, canvas: &mut WindowCanvas, renderer: &mut Renderer) {
for ref character in self.tokens.iter() {
character.render(canvas, renderer);
}
}
pub fn update_positions(&mut self, current: &mut Rect) {
for c in self.tokens.iter_mut() {
c.update_position(current);
}
}
}
impl Render for EditorFileSection {
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
let mut res = UpdateResult::NoOp;
for character in self.tokens.iter_mut() {
let r = character.render(canvas, renderer);
if res == UpdateResult::NoOp {
res = r;
}
}
res
}
}
impl Update for EditorFileSection {
fn update(&mut self, ticks: i32) -> UpdateResult {
let mut result = UpdateResult::NoOp;
for file_char in self.tokens.iter_mut() {
result = file_char.update(ticks)
}
result
}
}

View File

@ -2,116 +2,90 @@ use std::rc::Rc;
use sdl2::rect::Rect;
use sdl2::render::Texture;
use sdl2::ttf::Font;
use sdl2::pixels::Color;
use crate::lexer::TokenType;
use crate::renderer::Renderer;
use crate::renderer::managers::TextDetails;
use crate::renderer::resolve_color::resolve_color;
use crate::app::UpdateResult;
use crate::app::WindowCanvas;
use crate::app::{UpdateResult, WindowCanvas};
use crate::renderer::managers::FontDetails;
use crate::ui::*;
use crate::ui::text_character::*;
#[derive(Clone)]
pub struct EditorFileToken<'l> {
pos: usize,
text: String,
font_size: u16,
pub struct TextCharacterMeasure {
source: Rect,
dest: Rect,
token_type: TokenType,
texture: Option<Rc<Texture<'l>>>,
}
impl<'l> EditorFileToken<'l> {
pub fn new(renderer: &'l mut Renderer, pos: usize, token_type: TokenType) -> Self {
let c = match token_type {
_ if token_type.is_space() => "°".to_string(),
_ if token_type.is_new_line() => "\n".to_string(),
TokenType::Whitespace { .. } => "°".to_string(),
_ => token_type.get_text(),
};
let details = TextDetails {
text: c.clone(),
font_details: FontDetails::new(
renderer.config.editor_config.font_path.as_str(),
renderer.config.editor_config.character_size.clone(),
),
color: resolve_color(&token_type),
};
#[derive(Clone)]
pub struct EditorFileToken {
characters: Vec<TextCharacter>,
token_type: TokenType,
}
impl Into<Color> for TokenType {
fn into(self) -> Color {
match &self {
&TokenType::Whitespace { .. } => Color::RGBA(220, 220, 220, 90),
_ => Color::RGBA(0, 0, 0, 0),
}
}
}
impl EditorFileToken {
pub fn new(token_type: TokenType) -> Self {
Self {
pos,
text: c,
font_size: 0,
source: Rect::new(0, 0, 0, 0),
dest: Rect::new(0, 0, 0, 0),
characters: vec![],
token_type,
texture: renderer.render_text(details).clone(),
}
}
pub fn update(&mut self, _ticks: i32) -> UpdateResult {
// if self.font_size != config.editor_config.character_size {
// self.update_view(renderer);
// return UpdateResult::RefreshPositions;
// }
UpdateResult::NoOp
}
pub fn render(&self, canvas: &mut WindowCanvas, renderer: &mut Renderer) {
if self.token_type.is_new_line() {
return;
}
match &self.texture {
Some(texture) => {
renderer.render_texture(canvas, &texture, &self.source, &self.dest)
}
_ => {}
}
}
pub fn update_position(&mut self, current: &mut Rect) {
match self.token_type {
_ if self.token_type.is_new_line() => {
current.set_x(0);
current.set_y(
(self.token_type.line() as usize * self.source.height() as usize) as i32,
);
}
_ => {
self.dest.set_x(current.x());
self.dest.set_y(current.y());
self.dest.set_width(self.source.width());
self.dest.set_height(self.source.height());
current.set_x(self.dest.x() + self.source.width() as i32);
}
};
}
fn update_view(&mut self, renderer: &mut Renderer) {
self.font_size = renderer.config.editor_config.character_size.clone();
let font_details = FontDetails::new(
renderer.config.editor_config.font_path.as_str(),
self.font_size.clone(),
);
if let Ok(font) = renderer.font_manager.load(&font_details) {
if let Some((width, height)) = self.measure_text(&font) {
self.source.set_width(width as u32);
self.source.set_height(height as u32);
}
};
}
fn measure_text(&self, font: &Rc<Font>) -> Option<(usize, usize)> {
let mut w: usize = 0;
let mut h: usize = 0;
for c in self.text.chars() {
if let Ok((width, height)) = font.size_of_char(c) {
w += width as usize;
h = height as usize;
} else {
return None;
}
for text_character in self.characters.iter_mut() {
text_character.update_position(current);
}
Some((w, h))
}
fn update_view(&mut self, renderer: &mut Renderer) -> UpdateResult {
for c in self.token_type.text().chars() {
let mut text_character = TextCharacter::new(
c.clone(),
self.token_type.line(),
self.token_type.clone().into(),
);
text_character.update_view(renderer);
self.characters.push(text_character);
}
UpdateResult::RefreshPositions
}
}
impl Render for EditorFileToken {
/**
* Must first create targets so even if new line appear renderer will know
* where move render starting point
*/
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
if self.characters.is_empty() {
return self.update_view(renderer);
}
if self.token_type.is_new_line() {
return UpdateResult::NoOp;
}
for text_character in self.characters.iter_mut() {
text_character.render(canvas, renderer);
}
UpdateResult::NoOp
}
}
impl Update for EditorFileToken {
fn update(&mut self, ticks: i32) -> UpdateResult {
for text_character in self.characters.iter_mut() {
text_character.update(ticks);
}
UpdateResult::NoOp
}
}

View File

@ -14,6 +14,10 @@ pub enum TokenType {
String { token: Token },
Number { token: Token },
Identifier { token: Token },
Literal { token: Token },
Comment { token: Token },
Operator { token: Token },
Separator { token: Token },
}
impl TokenType {
@ -34,42 +38,34 @@ impl TokenType {
TokenType::Identifier { token } => TokenType::Identifier {
token: token.move_to(line, character, start, end),
},
TokenType::Literal { token } => TokenType::Literal {
token: token.move_to(line, character, start, end),
},
TokenType::Comment { token } => TokenType::Comment {
token: token.move_to(line, character, start, end),
},
TokenType::Operator { token } => TokenType::Operator {
token: token.move_to(line, character, start, end),
},
TokenType::Separator { token } => TokenType::Separator {
token: token.move_to(line, character, start, end),
},
}
}
pub fn is_new_line(&self) -> bool {
match self {
TokenType::Whitespace { token } => token.text() == "\n".to_string(),
TokenType::Whitespace { token } => token.text().as_str() == "\n",
_ => false,
}
}
pub fn is_space(&self) -> bool {
match self {
TokenType::Whitespace { token } => token.text() == " ".to_string(),
TokenType::Whitespace { token } => token.text().as_str() == " ",
_ => false,
}
}
pub fn get_start(&self) -> usize {
match self {
TokenType::Whitespace { token } => token.start(),
TokenType::Keyword { token } => token.start(),
TokenType::String { token } => token.start(),
TokenType::Number { token } => token.start(),
TokenType::Identifier { token } => token.start(),
}
}
pub fn get_text(&self) -> String {
match self {
TokenType::Whitespace { token } => token.text(),
TokenType::Keyword { token } => token.text(),
TokenType::String { token } => token.text(),
TokenType::Number { token } => token.text(),
TokenType::Identifier { token } => token.text(),
}
}
}
impl Deref for TokenType {
@ -82,6 +78,10 @@ impl Deref for TokenType {
TokenType::String { token } => token,
TokenType::Number { token } => token,
TokenType::Identifier { token } => token,
TokenType::Literal { token } => token,
TokenType::Comment { token } => token,
TokenType::Operator { token } => token,
TokenType::Separator { token } => token,
}
}
}
@ -112,8 +112,8 @@ impl Token {
}
}
pub fn text(&self) -> String {
self.text.clone()
pub fn text(&self) -> &String {
&self.text
}
pub fn line(&self) -> usize {
@ -146,7 +146,7 @@ impl Token {
pub fn parse(text: String, language: Language) -> Vec<TokenType> {
match language {
Language::PlainText => plain::lexer::Lexer::new(text.as_str())
.inspect(|tok| eprintln!("tok: {:?}", tok))
.inspect(|tok| println!("tok: {:?}", tok))
.map(|t| t.0)
.collect(),
}

View File

@ -1,14 +1,22 @@
#![allow(unused_imports)]
#![feature(use_extern_macros)]
extern crate plex;
extern crate rand;
extern crate sdl2;
extern crate dirs;
#[macro_use]
extern crate serde;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
pub mod app;
pub mod ui;
pub mod file;
pub mod lexer;
pub mod renderer;
pub mod themes;
use crate::app::Application;

View File

@ -26,16 +26,15 @@ pub struct FontDetails {
pub struct TextDetails {
pub text: String,
pub color: Color,
pub font_details: FontDetails,
pub font: FontDetails,
}
impl TextDetails {
pub fn get_cache_key(&self) -> String {
format!(
"text({}) size({}) {:?}",
self.text, self.font_details.size, self.color
)
.to_string()
self.text, self.font.size, self.color
).to_string()
}
}
@ -44,7 +43,7 @@ impl<'a> From<&'a TextDetails> for TextDetails {
Self {
text: details.text.clone(),
color: details.color.clone(),
font_details: details.font_details.clone(),
font: details.font.clone(),
}
}
}
@ -72,28 +71,28 @@ pub type FontManager<'l> = ResourceManager<'l, FontDetails, Font<'l, 'static>, S
#[derive(Clone)]
pub struct ResourceManager<'l, K, R, L>
where
K: Hash + Eq,
L: 'l + ResourceLoader<'l, R>,
where
K: Hash + Eq,
L: 'l + ResourceLoader<'l, R>,
{
loader: &'l L,
cache: HashMap<K, Rc<R>>,
}
impl<'l, K, R, L> ResourceManager<'l, K, R, L>
where
K: Hash + Eq,
L: ResourceLoader<'l, R>,
where
K: Hash + Eq,
L: ResourceLoader<'l, R>,
{
pub fn new(loader: &'l L) -> Self {
Self { cache: HashMap::new(), loader }
}
pub fn load<D>(&mut self, details: &D) -> Result<Rc<R>, String>
where
L: ResourceLoader<'l, R, Args = D>,
D: Eq + Hash + ?Sized,
K: Borrow<D> + for<'a> From<&'a D>,
where
L: ResourceLoader<'l, R, Args=D>,
D: Eq + Hash + ?Sized,
K: Borrow<D> + for<'a> From<&'a D>,
{
self.cache.get(details).cloned().map_or_else(
|| {
@ -104,6 +103,10 @@ where
Ok,
)
}
pub fn loader(&self) -> &L {
self.loader
}
}
impl<'l, T> ResourceLoader<'l, Texture<'l>> for TextureCreator<T> {
@ -124,25 +127,25 @@ impl<'l> ResourceLoader<'l, Font<'l, 'static>> for Sdl2TtfContext {
}
}
//impl<'l, T> TextureManager<'l, T> {
// pub fn load_text(
// &mut self,
// details: &mut TextDetails,
// font: &Font,
// ) -> Result<Rc<Texture<'l>>, String> {
// let key = details.get_cache_key();
// self.cache.get(key.as_str()).cloned().map_or_else(
// || {
// let surface = font
// .render(details.text.as_str())
// .blended(details.color)
// .unwrap();
// let texture = self.loader.create_texture_from_surface(&surface).unwrap();
// let resource = Rc::new(texture);
// self.cache.insert(key, resource.clone());
// Ok(resource)
// },
// Ok,
// )
// }
//}
impl<'l, T> TextureManager<'l, T> {
pub fn load_text(
&mut self,
details: &mut TextDetails,
font: &Rc<Font>,
) -> Result<Rc<Texture<'l>>, String> {
let key = details.get_cache_key();
self.cache.get(key.as_str()).cloned().map_or_else(
|| {
let surface = font
.render(details.text.as_str())
.blended(details.color)
.unwrap();
let texture = self.loader.create_texture_from_surface(&surface).unwrap();
let resource = Rc::new(texture);
self.cache.insert(key, resource.clone());
Ok(resource)
},
Ok,
)
}
}

View File

@ -1,5 +1,4 @@
pub mod managers;
pub mod resolve_color;
use crate::renderer::managers::{FontManager, TextureManager};
@ -18,7 +17,6 @@ pub struct Renderer<'a> {
pub config: Config,
pub font_manager: FontManager<'a>,
pub texture_manager: TextureManager<'a, WindowContext>,
pub texture_creator: TextureCreator<WindowContext>,
pub scroll: Point,
}
@ -26,13 +24,12 @@ impl<'a> Renderer<'a> {
pub fn new(
config: Config,
font_context: &'a Sdl2TtfContext,
texture_creator: TextureCreator<WindowContext>,
texture_creator: &'a TextureCreator<WindowContext>,
) -> Self {
Self {
config,
font_manager: FontManager::new(&font_context),
texture_manager: TextureManager::new(&texture_creator),
texture_creator,
scroll: (0, 0).into(),
}
}
@ -52,7 +49,7 @@ impl<'a> Renderer<'a> {
}
pub fn render_text(&mut self, details: TextDetails) -> Option<Rc<Texture>> {
let font = self.font_manager.load(&details.font_details).unwrap();
let font = self.font_manager.load(&details.font).unwrap();
let surface = font
.render(details.text.as_str())
.blended(details.color);
@ -62,7 +59,8 @@ impl<'a> Renderer<'a> {
return None;
};
let texture = self
.texture_creator
.texture_manager
.loader()
.create_texture_from_surface(&surface);
let texture = if let Ok(t) = texture {
Rc::new(t)

View File

@ -1,10 +0,0 @@
use sdl2::pixels::Color;
use crate::lexer::TokenType;
pub fn resolve_color(token_type: &TokenType) -> Color {
match token_type {
&TokenType::Whitespace { .. } => Color::RGBA(220, 220, 220, 90),
_ => Color::RGBA(0, 0, 0, 0),
}
}

376
src/themes/mod.rs Normal file
View File

@ -0,0 +1,376 @@
use std::fs;
use std::path::PathBuf;
use std::env;
use sdl2::pixels::Color;
use serde_json;
use serde::ser::{Serialize, Serializer, SerializeSeq, SerializeMap};
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct SerdeColor {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8
}
impl SerdeColor {
pub fn new(r: u8,g: u8,b: u8,a: u8) -> Self {
Self { r,g,b,a }
}
}
impl Into<Color> for SerdeColor {
fn into(self) -> Color {
Color {
r: self.r,
g: self.g,
b: self.b,
a: self.a
}
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct ThemeConfig {
color: SerdeColor,
italic: bool,
bold: bool,
}
impl ThemeConfig {
pub fn color(&self) -> &SerdeColor {
&self.color
}
pub fn italic(&self) -> bool {
self.italic
}
pub fn bold(&self) -> bool {
self.bold
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct CaretColor {
bright: ThemeConfig,
blur: ThemeConfig,
}
impl Default for CaretColor {
fn default() -> Self {
Self {
bright: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
italic: false,
bold: false,
},
blur: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
italic: false,
bold: false,
},
}
}
}
impl CaretColor {
pub fn bright(&self) -> &ThemeConfig {
&self.bright
}
pub fn blur(&self) -> &ThemeConfig {
&self.blur
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct CodeHighlightingColor {
whitespace: ThemeConfig,
keyword: ThemeConfig,
string: ThemeConfig,
number: ThemeConfig,
identifier: ThemeConfig,
literal: ThemeConfig,
comment: ThemeConfig,
operator: ThemeConfig,
separator: ThemeConfig,
}
impl Default for CodeHighlightingColor {
fn default() -> Self {
Self {
whitespace: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
bold: false,
italic: false,
},
keyword: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
bold: false,
italic: false,
},
string: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
bold: false,
italic: false,
},
number: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
bold: false,
italic: false,
},
identifier: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
bold: false,
italic: false,
},
literal: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
bold: false,
italic: false,
},
comment: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
bold: false,
italic: false,
},
operator: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
bold: false,
italic: false,
},
separator: ThemeConfig {
color: SerdeColor::new(0, 0, 0, 0),
bold: false,
italic: false,
},
}
}
}
impl CodeHighlightingColor {
pub fn whitespace(&self) -> &ThemeConfig {
&self.whitespace
}
pub fn keyword(&self) -> &ThemeConfig {
&self.keyword
}
pub fn string(&self) -> &ThemeConfig {
&self.string
}
pub fn number(&self) -> &ThemeConfig {
&self.number
}
pub fn identifier(&self) -> &ThemeConfig {
&self.identifier
}
pub fn literal(&self) -> &ThemeConfig {
&self.literal
}
pub fn comment(&self) -> &ThemeConfig {
&self.comment
}
pub fn operator(&self) -> &ThemeConfig {
&self.operator
}
pub fn separator(&self) -> &ThemeConfig {
&self.separator
}
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct Theme {
name: String,
background: SerdeColor,
caret: CaretColor,
code_highlighting: CodeHighlightingColor,
}
impl Default for Theme {
fn default() -> Self {
Self {
name: "Default".to_string(),
background: SerdeColor::new(255, 255, 255, 0),
caret: CaretColor::default(),
code_highlighting: CodeHighlightingColor::default(),
}
}
}
impl Theme {
pub fn name(&self) -> &String {
&self.name
}
pub fn background(&self) -> &SerdeColor {
&self.background
}
pub fn caret(&self) -> &CaretColor {
&self.caret
}
pub fn code_highlighting(&self) -> &CodeHighlightingColor {
&self.code_highlighting
}
fn railscasts() -> Self {
Self {
name: "railscasts".to_string(),
background: SerdeColor {
r: 60,
g: 60,
b: 60,
a: 0
},
caret: CaretColor { bright: ThemeConfig {
color: SerdeColor {
r: 0,
g: 0,
b: 0,
a: 0
},
italic: false,
bold: false
}, blur: ThemeConfig {
color: SerdeColor {
r: 0,
g: 0,
b: 0,
a: 0
},
italic: false,
bold: false
} },
code_highlighting: CodeHighlightingColor {
whitespace: ThemeConfig {
color: SerdeColor {
r: 0,
g: 0,
b: 0,
a: 0
},
italic: false,
bold: false
},
keyword: ThemeConfig {
color: SerdeColor {
r: 203,
g: 120,
b: 50,
a: 0
},
italic: false,
bold: true
},
string: ThemeConfig {
color: SerdeColor {
r: 0,
g: 0,
b: 0,
a: 0
},
italic: false,
bold: false
},
number: ThemeConfig {
color: SerdeColor {
r: 0,
g: 0,
b: 0,
a: 0
},
italic: false,
bold: false
},
identifier: ThemeConfig {
color: SerdeColor {
r: 0,
g: 0,
b: 0,
a: 0
},
italic: false,
bold: false
},
literal: ThemeConfig {
color: SerdeColor {
r: 0,
g: 0,
b: 0,
a: 0
},
italic: false,
bold: false
},
comment: ThemeConfig {
color: SerdeColor {
r: 188,
g: 147,
b: 88,
a: 0
},
italic: true,
bold: false
},
operator: ThemeConfig {
color: SerdeColor {
r: 0,
g: 0,
b: 0,
a: 0
},
italic: false,
bold: false
},
separator: ThemeConfig {
color: SerdeColor {
r: 0,
g: 0,
b: 0,
a: 0
},
italic: false,
bold: false
}
}
}
}
pub fn load(_theme_name: String) -> Self {
use dirs;
let home_dir = dirs::config_dir().unwrap();
let mut config_dir = home_dir.clone();
config_dir.push("rider/themes");
fs::create_dir_all(&config_dir)
.unwrap_or_else(|_| panic!("Cannot create config directory"));
let theme = Self::load_content(&config_dir, "default.json");
println!("theme config:\n{:?}", theme);
theme
}
fn load_content(config_dir: &PathBuf, file_name: &str) -> Theme {
let mut config_file = config_dir.clone();
config_file.push(file_name);
let contents = match fs::read_to_string(&config_file) {
Ok(s) => s,
Err(_) => {
let contents = serde_json::to_string_pretty(&Theme::default())
.unwrap();
fs::write(&config_file, contents.clone())
.unwrap_or_else(|_| panic!("Failed to crate theme config file"));
contents.to_string()
}
};
serde_json::from_str(&contents).unwrap_or_default()
}
}

68
src/ui/caret.rs Normal file
View File

@ -0,0 +1,68 @@
use sdl2::rect::Rect;
use sdl2::render::Texture;
use sdl2::pixels::Color;
use crate::app::{WindowCanvas, UpdateResult};
use crate::ui::*;
use crate::ui::text_character::TextCharacter;
use crate::renderer::Renderer;
const CARET_CHARACTER: char = '│';
#[derive(Clone, Debug, PartialEq)]
enum CaretState {
Bright,
Blur,
}
#[derive(Clone)]
pub struct Caret {
state: CaretState,
bright_character: TextCharacter,
blur_character: TextCharacter,
blink_delay: u8,
}
impl Caret {
pub fn new() -> Self {
Self {
bright_character: TextCharacter::new(CARET_CHARACTER, 0, Color::RGBA(0, 0, 0, 0)),
blur_character: TextCharacter::new(CARET_CHARACTER, 0, Color::RGBA(100, 100, 100, 0)),
state: CaretState::Bright,
blink_delay: 0,
}
}
fn toggle_state(&mut self) {
self.state = if self.state == CaretState::Bright {
CaretState::Blur
} else {
CaretState::Bright
};
}
}
impl Render for Caret {
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
match self.state {
CaretState::Bright => {
self.bright_character.update_position(&mut Rect::new(100, 220, 0, 0));
self.bright_character.render(canvas, renderer)
},
CaretState::Blur => {
self.blur_character.update_position(&mut Rect::new(100, 220, 0, 0));
self.blur_character.render(canvas, renderer)
},
}
}
}
impl Update for Caret {
fn update(&mut self, _ticks: i32) -> UpdateResult {
self.blink_delay += 1;
if self.blink_delay >= 30 {
self.blink_delay = 0;
self.toggle_state();
}
UpdateResult::NoOp
}
}

13
src/ui/mod.rs Normal file
View File

@ -0,0 +1,13 @@
pub mod caret;
pub mod text_character;
use crate::renderer::Renderer;
use crate::app::{WindowCanvas,UpdateResult};
pub trait Render {
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult;
}
pub trait Update {
fn update(&mut self, ticks: i32) -> UpdateResult;
}

141
src/ui/text_character.rs Normal file
View File

@ -0,0 +1,141 @@
use std::rc::Rc;
use sdl2::rect::Rect;
use sdl2::render::Texture;
use sdl2::ttf::Font;
use sdl2::pixels::Color;
use crate::lexer::TokenType;
use crate::renderer::Renderer;
use crate::renderer::managers::TextDetails;
use crate::app::{UpdateResult, WindowCanvas};
use crate::renderer::managers::FontDetails;
use crate::ui::*;
#[derive(Clone)]
pub struct TextCharacter {
pending: bool,
text_character: char,
line: usize,
source: Rect,
dest: Rect,
color: Color,
}
impl TextCharacter {
pub fn new(text_character: char, line: usize, color: Color) -> Self {
Self {
pending: true,
text_character,
line,
source: Rect::new(0, 0, 0, 0),
dest: Rect::new(0, 0, 0, 0),
color,
}
}
pub fn dest(&self) -> &Rect {
&self.dest
}
pub fn source(&self) -> &Rect {
&self.source
}
pub fn color(&self) -> &Color {
&self.color
}
pub fn update_position(&mut self, current: &mut Rect) {
if self.is_new_line() {
let y = (self.line * self.source.height() as usize) as i32;
current.set_x(0);
current.set_y(y);
} else {
self.dest.set_x(current.x());
self.dest.set_y(current.y());
self.dest.set_width(self.source.width());
self.dest.set_height(self.source.height());
current.set_x(self.dest.x() + self.source.width() as i32);
}
}
pub fn update_view(&mut self, renderer: &mut Renderer) -> UpdateResult {
let config = &renderer.config.editor_config;
let font_details = FontDetails::new(
config.font_path.as_str(),
config.character_size.clone(),
);
let font = renderer.font_manager
.load(&font_details)
.unwrap_or_else(|_| panic!("Font not found {:?}", font_details));
let c = self.text_character.clone();
if let Ok((width, height)) = font.size_of_char(c) {
self.source = Rect::new(0, 0, width, height);
self.dest = Rect::new(0, 0, width, height);
}
let mut details = TextDetails {
text: c.to_string(),
color: self.color.clone(),
font: font_details.clone(),
};
renderer.texture_manager
.load_text(&mut details, &font)
.unwrap_or_else(|_| panic!("Could not create texture for {:?}", c));
println!("texture for '{}' created", self.text_character);
self.pending = false;
UpdateResult::RefreshPositions
}
#[inline]
fn is_new_line(&self) -> bool {
self.text_character == '\n'
}
#[inline]
fn is_pending(&self) -> bool {
self.pending
}
}
impl Render for TextCharacter {
/**
* Must first create targets so even if new line appear renderer will know
* where move render starting point
*/
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
if self.is_pending() {
return self.update_view(renderer);
}
if self.is_new_line() {
return UpdateResult::NoOp;
}
let config = &renderer.config.editor_config;
let font_details = FontDetails::new(
config.font_path.as_str(),
config.character_size.clone(),
);
let font = renderer.font_manager
.load(&font_details)
.unwrap_or_else(|_| panic!("Could not load font for {:?}", font_details));
let c = self.text_character.clone();
let mut details = TextDetails {
text: c.to_string(),
color: self.color.clone(),
font: font_details.clone(),
};
if let Ok(texture) = renderer.texture_manager.load_text(&mut details, &font) {
renderer.render_texture(canvas, &texture, &self.source, &self.dest);
}
UpdateResult::NoOp
}
}
impl Update for TextCharacter {
fn update(&mut self, _ticks: i32) -> UpdateResult {
UpdateResult::NoOp
}
}