diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 80d9ea2..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,841 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "adler32" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "aho-corasick" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "arrayref" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "arrayvec" -version = "0.4.11" -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 = "atty" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "autocfg" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "backtrace" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "blake2b_simd" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "byteorder" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bzip2" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "c2-chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "chrono" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "clap" -version = "2.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cmake" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crc32fast" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "dirs" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "dirs-sys" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "dtoa" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "espanso" -version = "0.1.0" -dependencies = [ - "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", - "simplelog 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zip 0.5.3 (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.37 (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.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "flate2" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "getrandom" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "itoa" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.62" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "linked-hash-map" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log-panics" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "miniz_oxide" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.3 (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]] -name = "num-integer" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "podio" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ppv-lite86" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -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-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_users" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "remove_dir_all" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rust-argon2" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ryu" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_yaml" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "simplelog" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (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 = "syn" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synstructure" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (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 = "tempfile" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "term" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-width" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "vec_map" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wasi" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "widestring" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "yaml-rust" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zip" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" -"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2" -"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" -"checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499" -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" -"checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" -"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" -"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" -"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" -"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" -"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 flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2adaffba6388640136149e18ed080b77a78611c1e1d6de75aedcdf78df5d4682" -"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" -"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae0136257df209261daa18d6c16394757c63e032e27aafd8b07788b051082bef" -"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" -"checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" -"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" -"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" -"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" -"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" -"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" -"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" -"checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" -"checksum simplelog 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe8c881061cce7ee205784634eda7a61922925e7cc2833188467d3a560e027" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" -"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" -"checksum zip 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3c21bb410afa2bd823a047f5bda3adb62f51074ac7e06263b2c97ecdd47e9fc6" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 991b459..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "espanso" -version = "0.1.0" -authors = ["Federico Terzi "] -license = "GPL-3.0" -description = "Cross-platform Text Expander written in Rust" -readme = "README.md" -homepage = "https://github.com/federico-terzi/espanso" -edition = "2018" -build="build.rs" - -[dependencies] -widestring = "0.4.0" -serde = { version = "1.0", features = ["derive"] } -serde_yaml = "0.8" -dirs = "2.0.2" -clap = "2.33.0" -regex = "1.3.1" -log = "0.4.8" -simplelog = "0.7.1" -zip = "0.5.3" -fs2 = "0.4.3" -serde_json = "1.0.40" -log-panics = {version = "2.0.0", features = ["with-backtrace"]} -backtrace = "0.3.37" -chrono = "0.4.9" -lazy_static = "1.4.0" - -[target.'cfg(unix)'.dependencies] -libc = "0.2.62" - -[dev-dependencies] -tempfile = "3.1.0" - -[build-dependencies] -cmake = "0.1.31" \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index c8d63ef..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,37 +0,0 @@ -# Starter pipeline -# Start with a minimal pipeline that you can customize to build and deploy your code. -# Add steps that build, run tests, deploy, and more: -# https://aka.ms/yaml - -trigger: -- master - -jobs: - - job: Linux - pool: - vmImage: 'ubuntu-latest' - steps: - - script: | - sudo apt -y update - sudo apt install -y libxtst-dev libx11-dev libxdo3 libxdo-dev - displayName: Install library dependencies - - template: ci/test.yml - - template: ci/build-linux.yml - - template: ci/deploy.yml - - - job: macOS - pool: - vmImage: 'macOS-10.14' - steps: - - template: ci/test.yml - - template: ci/build-macos.yml - - template: ci/deploy.yml - - template: ci/publish-homebrew.yml - - - job: Windows - pool: - vmImage: 'windows-2019' - steps: - - template: ci/test.yml - - template: ci/build-win.yml - - template: ci/deploy.yml \ No newline at end of file diff --git a/build.rs b/build.rs deleted file mode 100644 index a415c03..0000000 --- a/build.rs +++ /dev/null @@ -1,55 +0,0 @@ -extern crate cmake; -use cmake::Config; -use std::path::PathBuf; - -/* OS SPECIFIC CONFIGS */ - -#[cfg(target_os = "windows")] -fn get_config() -> PathBuf { - Config::new("native/libwinbridge").build() -} - -#[cfg(target_os = "linux")] -fn get_config() -> PathBuf { - Config::new("native/liblinuxbridge").build() -} - -#[cfg(target_os = "macos")] -fn get_config() -> PathBuf { - Config::new("native/libmacbridge").build() -} - -/* - OS CUSTOM CARGO CONFIG LINES - Note: this is where linked libraries should be specified. -*/ - -#[cfg(target_os = "windows")] -fn print_config() { - println!("cargo:rustc-link-lib=static=winbridge"); - println!("cargo:rustc-link-lib=dylib=user32"); -} - -#[cfg(target_os = "linux")] -fn print_config() { - println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/"); - println!("cargo:rustc-link-lib=static=linuxbridge"); - println!("cargo:rustc-link-lib=dylib=X11"); - println!("cargo:rustc-link-lib=dylib=Xtst"); - println!("cargo:rustc-link-lib=dylib=xdo"); -} - -#[cfg(target_os = "macos")] -fn print_config() { - println!("cargo:rustc-link-lib=dylib=c++"); - println!("cargo:rustc-link-lib=static=macbridge"); - println!("cargo:rustc-link-lib=framework=Cocoa"); -} - -fn main() -{ - let dst = get_config(); - - println!("cargo:rustc-link-search=native={}", dst.display()); - print_config(); -} \ No newline at end of file diff --git a/ci/build-linux.yml b/ci/build-linux.yml deleted file mode 100644 index 6fb6721..0000000 --- a/ci/build-linux.yml +++ /dev/null @@ -1,9 +0,0 @@ -steps: - - script: | - cargo build --release - cd target/release/ - tar czf "espanso-linux.tar.gz" espanso - cd ../.. - cp target/release/espanso-*.gz . - ls -la - displayName: "Cargo build and packaging for Linux" \ No newline at end of file diff --git a/ci/build-macos.yml b/ci/build-macos.yml deleted file mode 100644 index ea7bee9..0000000 --- a/ci/build-macos.yml +++ /dev/null @@ -1,18 +0,0 @@ -steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.7.4' - addToPath: true - - - script: | - python --version - python -m pip install toml click - displayName: Installing python dependencies - - - script: | - set -e - python packager.py build - cp target/packager/mac/espanso-*.gz . - cp target/packager/mac/espanso.rb . - ls -la - displayName: "Cargo build and packaging for MacOS" \ No newline at end of file diff --git a/ci/build-win.yml b/ci/build-win.yml deleted file mode 100644 index 726a210..0000000 --- a/ci/build-win.yml +++ /dev/null @@ -1,17 +0,0 @@ -steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.7.4' - addToPath: true - - - script: | - python --version - python -m pip install toml click - displayName: Installing python dependencies - - - script: | - python packager.py build - copy "target\\packager\\win\\espanso-win-installer.exe" "espanso-win-installer.exe" - dir - displayName: "Build and packaging for Windows" - diff --git a/ci/deploy.yml b/ci/deploy.yml deleted file mode 100644 index d429d6d..0000000 --- a/ci/deploy.yml +++ /dev/null @@ -1,35 +0,0 @@ -parameters: - github: - isPreRelease: false - repositoryName: '$(Build.Repository.Name)' - gitHubConnection: "MyGithubConnection" - dependsOn: [] - displayName: "Release to github" - -steps: - - script: | - VER=$(cat Cargo.toml| grep version -m 1 | awk -F '"' '{ print $2 }') - echo '##vso[task.setvariable variable=vers]'v$VER - condition: not(eq(variables['Agent.OS'], 'Windows_NT')) - displayName: Obtain version from Cargo.toml on Unix - - - powershell: | - Select-String -Path "Cargo.toml" -Pattern "version" | Select-Object -First 1 -outvariable v - $vv = [regex]::match($v, '"([^"]+)"').Groups[1].Value - echo "##vso[task.setvariable variable=vers]v$vv" - condition: eq(variables['Agent.OS'], 'Windows_NT') - displayName: Obtain version from Cargo.toml on Windows - - - task: GitHubRelease@0 - displayName: Create GitHub release - inputs: - gitHubConnection: ${{ parameters.github.gitHubConnection }} - tagSource: manual - title: '$(vers)' - tag: '$(vers)' - assetUploadMode: replace - action: edit - assets: 'espanso-*' - addChangeLog: false - repositoryName: ${{ parameters.github.repositoryName }} - isPreRelease: ${{ parameters.github.isPreRelease }} \ No newline at end of file diff --git a/ci/install-rust.yml b/ci/install-rust.yml deleted file mode 100644 index ca9e2c4..0000000 --- a/ci/install-rust.yml +++ /dev/null @@ -1,35 +0,0 @@ -# defaults for any parameters that aren't specified -parameters: - rust_version: stable - -steps: - # Linux and macOS. - - script: | - set -e - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" - env: - RUSTUP_TOOLCHAIN: ${{parameters.rust_version}} - displayName: "Install rust (*nix)" - condition: not(eq(variables['Agent.OS'], 'Windows_NT')) - # Windows. - - script: | - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN% - set PATH=%PATH%;%USERPROFILE%\.cargo\bin - echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" - env: - RUSTUP_TOOLCHAIN: ${{parameters.rust_version}} - displayName: "Install rust (windows)" - condition: eq(variables['Agent.OS'], 'Windows_NT') - # Install additional components: - - ${{ each component in parameters.components }}: - - script: rustup component add ${{ component }} - - # All platforms. - - script: | - rustup -V - rustup component list --installed - rustc -Vv - cargo -V - displayName: Query rust and cargo versions \ No newline at end of file diff --git a/ci/publish-homebrew.yml b/ci/publish-homebrew.yml deleted file mode 100644 index d5ea1cb..0000000 --- a/ci/publish-homebrew.yml +++ /dev/null @@ -1,21 +0,0 @@ -steps: - - task: InstallSSHKey@0 - inputs: - knownHostsEntry: "github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" - sshPublicKey: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsB9zcHN84/T5URAsfIpb52HnJl2kUK7WWXyV9pFXaO6yz722JxzVq56J3TTrcUCDhM3DKSGKivB6n/tmLw4mefcY3t7kh8puAtaNrNnB4TWqVPFHZtnpYuYslp1rM92r7Bz1FHfVfsDZxqSWlGU/lp0gNEEgXbr2PCExbCh3TGTsKePARhMAtPEvyEZk1+8uA/HvUTjhuDp7P+BbejAsqtgVF0QoEvqDE5af8DZY6+i1cHRgwBYgSnOus8FHsZUGMyAJQtb+dD7imGw/nzokPJzbmQJwQetyhp52CfThpAm12EFtIU43imb8nndlVAmsIHF6czbmI5LP3U0UcTLct freddy@freddy-Z97M-DS3H" - sshKeySecureFile: "azuressh" - - - script: | - set -ex - cat ~/.ssh/known_hosts - git config --global user.email "federicoterzi96@gmail.com" - git config --global user.email "Federico Terzi" - VER=$(cat Cargo.toml| grep version -m 1 | awk -F '"' '{ print $2 }') - git clone git@github.com:federico-terzi/homebrew-espanso.git - rm homebrew-espanso/Formula/espanso.rb - cp espanso.rb homebrew-espanso/Formula/espanso.rb - cd homebrew-espanso - git add -A - git commit -m "Update to version: $VER" - git push - displayName: "Publishing to Homebrew" \ No newline at end of file diff --git a/ci/test.yml b/ci/test.yml deleted file mode 100644 index 13decb1..0000000 --- a/ci/test.yml +++ /dev/null @@ -1,16 +0,0 @@ -parameters: - rust_version: stable - -steps: - - template: install-rust.yml - - - script: | - set -e - cargo test --release - displayName: Cargo tests on Unix - condition: not(eq(variables['Agent.OS'], 'Windows_NT')) - - - script: | - cargo test --release - displayName: Cargo tests on Windows - condition: eq(variables['Agent.OS'], 'Windows_NT') \ No newline at end of file diff --git a/images/accessibility-macos-enable.png b/images/accessibility-macos-enable.png deleted file mode 100644 index 58af7cc..0000000 Binary files a/images/accessibility-macos-enable.png and /dev/null differ diff --git a/images/accessibility-prompt.png b/images/accessibility-prompt.png deleted file mode 100644 index dbaeff9..0000000 Binary files a/images/accessibility-prompt.png and /dev/null differ diff --git a/images/donate.gif b/images/donate.gif deleted file mode 100644 index d91cb49..0000000 Binary files a/images/donate.gif and /dev/null differ diff --git a/images/espanso-icon-macos-statusbar.png b/images/espanso-icon-macos-statusbar.png deleted file mode 100644 index 6253dad..0000000 Binary files a/images/espanso-icon-macos-statusbar.png and /dev/null differ diff --git a/images/example.gif b/images/example.gif deleted file mode 100644 index cb08403..0000000 Binary files a/images/example.gif and /dev/null differ diff --git a/images/icongreensmall.png b/images/icongreensmall.png deleted file mode 100644 index 9bde0d2..0000000 Binary files a/images/icongreensmall.png and /dev/null differ diff --git a/images/titlebar.png b/images/titlebar.png deleted file mode 100644 index 5769989..0000000 Binary files a/images/titlebar.png and /dev/null differ diff --git a/images/windows-smartscreen.png b/images/windows-smartscreen.png deleted file mode 100644 index 3e238ba..0000000 Binary files a/images/windows-smartscreen.png and /dev/null differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..fe6894f --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + espanso + + + +

Coming soon

+ + \ No newline at end of file diff --git a/native/liblinuxbridge/CMakeLists.txt b/native/liblinuxbridge/CMakeLists.txt deleted file mode 100644 index 4f44763..0000000 --- a/native/liblinuxbridge/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -cmake_minimum_required(VERSION 3.0) -project(liblinuxbridge) - -set (CMAKE_CXX_STANDARD 14) -set(CMAKE_REQUIRED_INCLUDES "/usr/local/include" "/usr/include") - -add_library(linuxbridge STATIC bridge.cpp bridge.h) - -install(TARGETS linuxbridge DESTINATION .) \ No newline at end of file diff --git a/native/liblinuxbridge/bridge.cpp b/native/liblinuxbridge/bridge.cpp deleted file mode 100644 index d8d4012..0000000 --- a/native/liblinuxbridge/bridge.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#include "bridge.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -extern "C" { // Needed to avoid C++ compiler name mangling - #include -} - -/* -This code uses the X11 Record Extension to receive keyboard -events. Documentation of this library can be found here: -https://www.x.org/releases/X11R7.6/doc/libXtst/recordlib.html - -We will refer to this extension as RE from now on. -*/ - -/* -This struct is needed to receive events from the RE. -The funny thing is: it's not defined there, it should though. -The only place this is mentioned is the libxnee library, -so check that out if you need a reference. -*/ -typedef union { - unsigned char type ; - xEvent event ; - xResourceReq req ; - xGenericReply reply ; - xError error ; - xConnSetupPrefix setup; -} XRecordDatum; - -/* -Connections to the X server, RE recommends 2 connections: -one for recording control and one for reading the recorded data. -*/ -Display *data_disp = NULL; -Display *ctrl_disp = NULL; - -XRecordRange *record_range; -XRecordContext context; - -xdo_t * xdo_context; - -// Callback invoked when a new key event occur. -void event_callback (XPointer, XRecordInterceptData*); - -KeypressCallback keypress_callback; -void * context_instance; - -void register_keypress_callback(KeypressCallback callback) { - keypress_callback = callback; -} - - -int32_t initialize(void * _context_instance) { - setlocale(LC_ALL, ""); - - context_instance = _context_instance; - - /* - Open the connections to the X server. - RE recommends to open 2 connections to the X server: - one for the recording control and one to read the protocol - data. - */ - ctrl_disp = XOpenDisplay(NULL); - data_disp = XOpenDisplay(NULL); - - if (!ctrl_disp || !data_disp) { // Display error - return -1; - } - - /* - We must set the ctrl_disp to sync mode, or, when we the enable - context in data_disp, there will be a fatal X error. - */ - XSynchronize(ctrl_disp, True); - - int dummy; - - // Make sure the X RE is installed in this system. - if (!XRecordQueryVersion(ctrl_disp, &dummy, &dummy)) { - return -2; - } - - // Make sure the X Keyboard Extension is installed - if (!XkbQueryExtension(ctrl_disp, &dummy, &dummy, &dummy, &dummy, &dummy)) { - return -3; - } - - // Initialize the record range, that is the kind of events we want to track. - record_range = XRecordAllocRange (); - if (!record_range) { - return -4; - } - record_range->device_events.first = KeyPress; - record_range->device_events.last = KeyRelease; - - // We want to get the keys from all clients - XRecordClientSpec client_spec; - client_spec = XRecordAllClients; - - // Initialize the context - context = XRecordCreateContext(ctrl_disp, 0, &client_spec, 1, &record_range, 1); - if (!context) { - return -5; - } - - xdo_context = xdo_new(NULL); - - return 1; -} - -int32_t eventloop() { - if (!XRecordEnableContext (data_disp, context, event_callback, NULL)) { - return -1; - } - - return 1; -} - -void cleanup() { - XRecordDisableContext(ctrl_disp, context); - XRecordFreeContext(ctrl_disp, context); - XFree (record_range); - XCloseDisplay(data_disp); - XCloseDisplay(ctrl_disp); - xdo_free(xdo_context); -} - -void event_callback(XPointer p, XRecordInterceptData *hook) -{ - // Make sure the event comes from the X11 server - if (hook->category != XRecordFromServer) { - XRecordFreeData(hook); - return; - } - - // Cast the event payload to a XRecordDatum, needed later to access the fields - // This struct was hard to find and understand. Turn's out that all the - // required data are included in the "event" field of this structure. - // The funny thing is that it's not a XEvent as one might expect, - // but a xEvent, a very different beast defined in the Xproto.h header. - // I suggest you to look at that header if you want to understand where the - // upcoming field where taken from. - XRecordDatum *data = (XRecordDatum*) hook->data; - - int event_type = data->type; - int key_code = data->event.u.u.detail; - - // In order to convert the key_code into the corresponding string, - // we need to synthesize an artificial XKeyEvent, to feed later to the - // XLookupString function. - XKeyEvent event; - event.display = ctrl_disp; - event.window = data->event.u.focus.window; - event.root = XDefaultRootWindow(ctrl_disp); - event.subwindow = None; - event.time = data->event.u.keyButtonPointer.time; - event.x = 1; - event.y = 1; - event.x_root = 1; - event.y_root = 1; - event.same_screen = True; - event.keycode = key_code; - event.state = data->event.u.keyButtonPointer.state; - event.type = KeyPress; - - // Extract the corresponding chars. - std::array buffer; - int res = XLookupString(&event, buffer.data(), buffer.size(), NULL, NULL); - - switch (event_type) { - case KeyPress: - //printf ("%d %d %s\n", key_code, res, buffer.data()); - if (res > 0 && key_code != 22) { // Printable character, but not backspace - keypress_callback(context_instance, buffer.data(), buffer.size(), 0, key_code); - }else{ // Modifier key - keypress_callback(context_instance, NULL, 0, 1, key_code); - } - break; - default: - break; - } - - XRecordFreeData(hook); -} - -void send_string(const char * string) { - xdo_enter_text_window(xdo_context, CURRENTWINDOW, string, 12000); -} - -void delete_string(int32_t count) { - for (int i = 0; i 0) { - if (strstr(class_buffer, "terminal") != NULL) { - return 1; - } - } - - return 0; -} diff --git a/native/liblinuxbridge/bridge.h b/native/liblinuxbridge/bridge.h deleted file mode 100644 index 89d60aa..0000000 --- a/native/liblinuxbridge/bridge.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#ifndef ESPANSO_BRIDGE_H -#define ESPANSO_BRIDGE_H - -#include - -extern void * context_instance; - -/* - * Initialize the X11 context and parameters - */ -extern "C" int32_t initialize(void * context_instance); - -/* - * Start the event loop indefinitely. Blocking call. - */ -extern "C" int32_t eventloop(); - -/* - * Clean all the X11 resources allocated during the initialization. - */ -extern "C" void cleanup(); - -/* - * Called when a new keypress is made, the first argument is an char array, - * while the second is the size of the array. - */ -typedef void (*KeypressCallback)(void * self, const char *buffer, int32_t len, int32_t is_modifier, int32_t key_code); - -extern KeypressCallback keypress_callback; - -/* - * Register the callback that will be called when a keypress was made - */ -extern "C" void register_keypress_callback(KeypressCallback callback); - -/* - * Type the given string by simulating Key Presses - */ -extern "C" void send_string(const char * string); - -/* - * Send the backspace keypress, *count* times. - */ -extern "C" void delete_string(int32_t count); - -/* - * Trigger normal paste ( Pressing CTRL+V ) - */ -extern "C" void trigger_paste(); - -/* - * Trigger terminal paste ( Pressing CTRL+SHIFT+V ) - */ -extern "C" void trigger_terminal_paste(); - - -// SYSTEM MODULE - -/* - * Return the active windows's WM_NAME - */ -extern "C" int32_t get_active_window_name(char * buffer, int32_t size); - -/* - * Return the active windows's WM_CLASS - */ -extern "C" int32_t get_active_window_class(char * buffer, int32_t size); - -/* - * Return the active windows's executable path - */ -extern "C" int32_t get_active_window_executable(char * buffer, int32_t size); - -/* - * Return 1 if the current window is a terminal window, 0 otherwise. - */ -extern "C" int32_t is_current_window_terminal(); - -#endif //ESPANSO_BRIDGE_H diff --git a/native/libmacbridge/AppDelegate.h b/native/libmacbridge/AppDelegate.h deleted file mode 100644 index f35f5d1..0000000 --- a/native/libmacbridge/AppDelegate.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#import -#import - -#include "bridge.h" - -@interface AppDelegate : NSObject { - @public NSStatusItem *myStatusItem; -} - -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification; -- (IBAction) statusIconClick: (id) sender; -- (IBAction) contextMenuClick: (id) sender; - -@end \ No newline at end of file diff --git a/native/libmacbridge/AppDelegate.mm b/native/libmacbridge/AppDelegate.mm deleted file mode 100644 index 35e9177..0000000 --- a/native/libmacbridge/AppDelegate.mm +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#import "AppDelegate.h" - -@implementation AppDelegate - -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification -{ - // Setup status icon - myStatusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain]; - - NSString *nsIconPath = [NSString stringWithUTF8String:icon_path]; - NSImage *statusImage = [[NSImage alloc] initWithContentsOfFile:nsIconPath]; - [statusImage setTemplate:YES]; - - [myStatusItem.button setImage:statusImage]; - [myStatusItem setHighlightMode:YES]; - [myStatusItem.button setAction:@selector(statusIconClick:)]; - [myStatusItem.button setTarget:self]; - - // Setup key listener - [NSEvent addGlobalMonitorForEventsMatchingMask:(NSEventMaskKeyDown | NSEventMaskFlagsChanged) - handler:^(NSEvent *event){ - if (event.type == NSEventTypeKeyDown - && event.keyCode != 0x33) { // Send backspace as a modifier - - const char * chars = [event.characters UTF8String]; - int len = event.characters.length; - - keypress_callback(context_instance, chars, len, 0, event.keyCode); - //NSLog(@"keydown: %@, %d", event.characters, event.keyCode); - }else{ - // Because this event is triggered for both the press and release of a modifier, trigger the callback - // only on release - if (([event modifierFlags] & (NSEventModifierFlagShift | NSEventModifierFlagCommand | - NSEventModifierFlagControl | NSEventModifierFlagOption)) == 0) { - - keypress_callback(context_instance, NULL, 0, 1, event.keyCode); - } - - //NSLog(@"keydown: %d", event.keyCode); - } - }]; -} - -- (IBAction) statusIconClick: (id) sender { - icon_click_callback(context_instance); -} - -- (IBAction) contextMenuClick: (id) sender { - NSInteger item_id = [[sender valueForKey:@"tag"] integerValue]; - - context_menu_click_callback(context_instance, static_cast(item_id)); -} - -@end \ No newline at end of file diff --git a/native/libmacbridge/CMakeLists.txt b/native/libmacbridge/CMakeLists.txt deleted file mode 100644 index 78689a7..0000000 --- a/native/libmacbridge/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -cmake_minimum_required(VERSION 3.0) -project(libmacbridge) - -set (CMAKE_CXX_STANDARD 11) -set(CMAKE_C_FLAGS "-x objective-c") - -add_library(macbridge STATIC bridge.mm bridge.h AppDelegate.h AppDelegate.mm) - -install(TARGETS macbridge DESTINATION .) \ No newline at end of file diff --git a/native/libmacbridge/bridge.h b/native/libmacbridge/bridge.h deleted file mode 100644 index 8f414d9..0000000 --- a/native/libmacbridge/bridge.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#ifndef ESPANSO_BRIDGE_H -#define ESPANSO_BRIDGE_H - -#include - -extern "C" { - -extern void * context_instance; -extern char * icon_path; - -/* -* Initialize the AppDelegate and check for accessibility permissions -*/ -int32_t initialize(void * context, const char * icon_path); - -/* - * Start the event loop indefinitely. Blocking call. - */ -int32_t eventloop(); - -/* - * Called when a new keypress is made, the first argument is an char array, - * while the second is the size of the array. - */ -typedef void (*KeypressCallback)(void * self, const char *buffer, int32_t len, int32_t is_modifier, int32_t key_code); - -extern KeypressCallback keypress_callback; - -/* - * Register the callback that will be called when a keypress was made - */ -void register_keypress_callback(KeypressCallback callback); - -/* - * Type the given string by using the CGEventKeyboardSetUnicodeString call - */ -void send_string(const char * string); - -/* - * Send the Virtual Key press - */ -void send_vkey(int32_t vk); - -/* - * Send the backspace keypress, *count* times. - */ -void delete_string(int32_t count); - -/* - * Trigger normal paste ( Pressing CMD+V ) - */ -void trigger_paste(); - -// UI - -/* - * Called when the tray icon is clicked - */ -typedef void (*IconClickCallback)(void * self); -extern IconClickCallback icon_click_callback; -void register_icon_click_callback(IconClickCallback callback); - -// CONTEXT MENU - -typedef struct { - int32_t id; - int32_t type; - char name[100]; -} MenuItem; - -int32_t show_context_menu(MenuItem * items, int32_t count); - -/* - * Called when the context menu is clicked - */ -typedef void (*ContextMenuClickCallback)(void * self, int32_t id); -extern ContextMenuClickCallback context_menu_click_callback; -extern "C" void register_context_menu_click_callback(ContextMenuClickCallback callback); - -// SYSTEM - -/* - * Check if espanso is authorized to control accessibility features, needed to detect key presses. - * @return - */ -int32_t check_accessibility(); - -/* - * Prompt to authorize the accessibility features. - * @return - */ -int32_t prompt_accessibility(); - -/* - * Open Security & Privacy settings panel - * @return - */ -void open_settings_panel(); - -/* - * Return the active NSRunningApplication path - */ -int32_t get_active_app_bundle(char * buffer, int32_t size); - -/* - * Return the active NSRunningApplication bundle identifier - */ -int32_t get_active_app_identifier(char * buffer, int32_t size); - -// CLIPBOARD - -/* - * Return the clipboard text - */ -int32_t get_clipboard(char * buffer, int32_t size); - -/* - * Set the clipboard text - */ -int32_t set_clipboard(char * text); - -}; -#endif //ESPANSO_BRIDGE_H diff --git a/native/libmacbridge/bridge.mm b/native/libmacbridge/bridge.mm deleted file mode 100644 index 361bfa3..0000000 --- a/native/libmacbridge/bridge.mm +++ /dev/null @@ -1,266 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#include "bridge.h" - -#import -#include "AppDelegate.h" -#include -#include -extern "C" { - -} - -#include - -void * context_instance; -char * icon_path; -AppDelegate * delegate_ptr; - -KeypressCallback keypress_callback; -IconClickCallback icon_click_callback; -ContextMenuClickCallback context_menu_click_callback; - -int32_t initialize(void * context, const char * _icon_path) { - context_instance = context; - icon_path = strdup(_icon_path); - - AppDelegate *delegate = [[AppDelegate alloc] init]; - delegate_ptr = delegate; - NSApplication * application = [NSApplication sharedApplication]; - [application setDelegate:delegate]; -} - -void register_keypress_callback(KeypressCallback callback) { - keypress_callback = callback; -} - -void register_icon_click_callback(IconClickCallback callback) { - icon_click_callback = callback; -} - -void register_context_menu_click_callback(ContextMenuClickCallback callback) { - context_menu_click_callback = callback; -} - - -int32_t eventloop() { - [NSApp run]; -} - -void send_string(const char * string) { - char * stringCopy = strdup(string); - dispatch_async(dispatch_get_main_queue(), ^(void) { - // Convert the c string to a UniChar array as required by the CGEventKeyboardSetUnicodeString method - NSString *nsString = [NSString stringWithUTF8String:stringCopy]; - CFStringRef cfString = (__bridge CFStringRef) nsString; - std::vector buffer(nsString.length); - CFStringGetCharacters(cfString, CFRangeMake(0, nsString.length), buffer.data()); - - free(stringCopy); - - // Send the event - - // Because of a bug ( or undocumented limit ) of the CGEventKeyboardSetUnicodeString method - // the string gets truncated after 20 characters, so we need to send multiple events. - - int i = 0; - while (i < buffer.size()) { - int chunk_size = 20; - if ((i+chunk_size) > buffer.size()) { - chunk_size = buffer.size() - i; - } - - UniChar * offset_buffer = buffer.data() + i; - CGEventRef e = CGEventCreateKeyboardEvent(NULL, 0x31, true); - CGEventKeyboardSetUnicodeString(e, chunk_size, offset_buffer); - CGEventPost(kCGHIDEventTap, e); - CFRelease(e); - - usleep(2000); - - i += chunk_size; - } - }); -} - -void delete_string(int32_t count) { - dispatch_async(dispatch_get_main_queue(), ^(void) { - for (int i = 0; i < count; i++) { - CGEventRef keydown; - keydown = CGEventCreateKeyboardEvent(NULL, 0x33, true); - CGEventPost(kCGHIDEventTap, keydown); - CFRelease(keydown); - - usleep(2000); - - CGEventRef keyup; - keyup = CGEventCreateKeyboardEvent(NULL, 0x33, false); - CGEventPost(kCGHIDEventTap, keyup); - CFRelease(keyup); - - usleep(2000); - } - }); -} - -void send_vkey(int32_t vk) { - dispatch_async(dispatch_get_main_queue(), ^(void) { - CGEventRef keydown; - keydown = CGEventCreateKeyboardEvent(NULL, vk, true); - CGEventPost(kCGHIDEventTap, keydown); - CFRelease(keydown); - - usleep(2000); - - CGEventRef keyup; - keyup = CGEventCreateKeyboardEvent(NULL, vk, false); - CGEventPost(kCGHIDEventTap, keyup); - CFRelease(keyup); - - usleep(2000); - }); -} - -void trigger_paste() { - dispatch_async(dispatch_get_main_queue(), ^(void) { - CGEventRef keydown; - keydown = CGEventCreateKeyboardEvent(NULL, 0x37, true); // CMD - CGEventPost(kCGHIDEventTap, keydown); - CFRelease(keydown); - - usleep(2000); - - CGEventRef keydown2; - keydown2 = CGEventCreateKeyboardEvent(NULL, 0x09, true); // V key - CGEventPost(kCGHIDEventTap, keydown2); - CFRelease(keydown2); - - usleep(2000); - - CGEventRef keyup; - keyup = CGEventCreateKeyboardEvent(NULL, 0x09, false); - CGEventPost(kCGHIDEventTap, keyup); - CFRelease(keyup); - - usleep(2000); - - CGEventRef keyup2; - keyup2 = CGEventCreateKeyboardEvent(NULL, 0x37, false); // CMD - CGEventPost(kCGHIDEventTap, keyup2); - CFRelease(keyup2); - - usleep(2000); - }); -} - -int32_t get_active_app_bundle(char * buffer, int32_t size) { - NSRunningApplication *frontApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; - NSString *bundlePath = [frontApp bundleURL].path; - const char * path = [bundlePath UTF8String]; - - snprintf(buffer, size, "%s", path); - - [bundlePath release]; - - return 1; -} - -int32_t get_active_app_identifier(char * buffer, int32_t size) { - NSRunningApplication *frontApp = [[NSWorkspace sharedWorkspace] frontmostApplication]; - NSString *bundleId = frontApp.bundleIdentifier; - const char * bundle = [bundleId UTF8String]; - - snprintf(buffer, size, "%s", bundle); - - [bundleId release]; - - return 1; -} - -int32_t get_clipboard(char * buffer, int32_t size) { - NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - for (id element in pasteboard.pasteboardItems) { - NSString *string = [element stringForType: NSPasteboardTypeString]; - if (string != NULL) { - const char * text = [string UTF8String]; - snprintf(buffer, size, "%s", text); - - [string release]; - - return 1; - } - } - - return -1; -} - -int32_t set_clipboard(char * text) { - NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - NSArray *array = @[NSPasteboardTypeString]; - [pasteboard declareTypes:array owner:nil]; - - NSString *nsText = [NSString stringWithUTF8String:text]; - [pasteboard setString:nsText forType:NSPasteboardTypeString]; -} - -// CONTEXT MENU - -int32_t show_context_menu(MenuItem * items, int32_t count) { - MenuItem * item_copy = (MenuItem*)malloc(sizeof(MenuItem)*count); - memcpy(item_copy, items, sizeof(MenuItem)*count); - int32_t count_copy = count; - - dispatch_async(dispatch_get_main_queue(), ^(void) { - - NSMenu *espansoMenu = [[NSMenu alloc] initWithTitle:@"Espanso"]; - - for (int i = 0; imyStatusItem popUpStatusItemMenu:espansoMenu]; - }); -} - -// 10.9+ only, see this url for compatibility: -// http://stackoverflow.com/questions/17693408/enable-access-for-assistive-devices-programmatically-on-10-9 -int32_t check_accessibility() { - NSDictionary* opts = @{(__bridge id)kAXTrustedCheckOptionPrompt: @NO}; - return AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)opts); -} - -int32_t prompt_accessibility() { - NSDictionary* opts = @{(__bridge id)kAXTrustedCheckOptionPrompt: @YES}; - return AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)opts); -} - -void open_settings_panel() { - NSString *urlString = @"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"; - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]]; -} diff --git a/native/libwinbridge/CMakeLists.txt b/native/libwinbridge/CMakeLists.txt deleted file mode 100644 index f0ae960..0000000 --- a/native/libwinbridge/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -cmake_minimum_required(VERSION 3.0) -project(libwinbridge) - -set (CMAKE_CXX_STANDARD 14) - -add_library(winbridge STATIC bridge.cpp bridge.h) - -install(TARGETS winbridge DESTINATION .) \ No newline at end of file diff --git a/native/libwinbridge/bridge.cpp b/native/libwinbridge/bridge.cpp deleted file mode 100644 index e5a4b27..0000000 --- a/native/libwinbridge/bridge.cpp +++ /dev/null @@ -1,644 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#include "bridge.h" -#include -#include -#include -#include -#include -#include - -#define UNICODE - -#include -#include -#include - -// How many milliseconds must pass between keystrokes to refresh the keyboard layout -const long refreshKeyboardLayoutInterval = 2000; - -void * manager_instance; - -// Keyboard listening - -DWORD lastKeyboardPressTick = 0; -HKL currentKeyboardLayout; -HWND window; -const wchar_t* const winclass = L"Espanso"; - - - -// UI - -#define APPWM_ICON_CLICK (WM_APP + 1) -#define APPWM_NOTIFICATION_POPUP (WM_APP + 2) -#define APPWM_NOTIFICATION_CLOSE (WM_APP + 3) -#define APPWM_SHOW_CONTEXT_MENU (WM_APP + 4) - -const wchar_t* const notification_winclass = L"EspansoNotification"; -HWND nw = NULL; -HWND hwnd_st_u = NULL; -HBITMAP g_espanso_bmp = NULL; -HICON g_espanso_ico = NULL; -NOTIFYICONDATA nid = {}; - -// Callbacks - -KeypressCallback keypress_callback = NULL; -IconClickCallback icon_click_callback = NULL; -ContextMenuClickCallback context_menu_click_callback = NULL; - -void register_keypress_callback(KeypressCallback callback) { - keypress_callback = callback; -} - -void register_icon_click_callback(IconClickCallback callback) { - icon_click_callback = callback; -} - -void register_context_menu_click_callback(ContextMenuClickCallback callback) { - context_menu_click_callback = callback; -} - -/* - * Message handler procedure for the windows - */ -LRESULT CALLBACK window_procedure(HWND window, unsigned int msg, WPARAM wp, LPARAM lp) -{ - HDC hdcStatic = NULL; - - switch (msg) - { - case WM_DESTROY: - std::cout << "\ndestroying window\n"; - PostQuitMessage(0); - DeleteObject(g_espanso_bmp); - DeleteObject(g_espanso_ico); - return 0L; - case WM_COMMAND: // Click on the tray icon context menu - { - UINT idItem = (UINT)LOWORD(wp); - UINT flags = (UINT)HIWORD(wp); - - if (flags == 0) { - context_menu_click_callback(manager_instance, (int32_t)idItem); - } - - break; - } - case APPWM_NOTIFICATION_POPUP: // Request to show a notification - { - std::unique_ptr ptr(reinterpret_cast(wp)); - - SetWindowText(hwnd_st_u, L" "); // Clear the previous text - SetWindowText(hwnd_st_u, ptr.get()); - - // Show the window - ShowWindow(nw, SW_SHOWNOACTIVATE); - break; - } - case APPWM_NOTIFICATION_CLOSE: // Request to close a notification - { - // Hide the window - ShowWindow(nw, SW_HIDE); - break; - } - case APPWM_SHOW_CONTEXT_MENU: // Request to show context menu - { - HMENU hPopupMenu = CreatePopupMenu(); - - // Create the menu - - int32_t count = static_cast(lp); - std::unique_ptr items(reinterpret_cast(wp)); - - for (int i = 0; i lpb(dwSize); - - // Request the Raw input data - if (GetRawInputData((HRAWINPUT)lp, RID_INPUT, lpb.data(), &dwSize, - sizeof(RAWINPUTHEADER)) != dwSize) { - return 0; - } - - // Convert the input data - RAWINPUT* raw = reinterpret_cast(lpb.data()); - - // Make sure it's a keyboard type event, relative to a key press. - if (raw->header.dwType == RIM_TYPEKEYBOARD) - { - // We only want KEY UP AND KEY DOWN events - if (raw->data.keyboard.Message != WM_KEYDOWN && raw->data.keyboard.Message != WM_KEYUP) { - return 0; - } - - int is_key_down = raw->data.keyboard.Message == WM_KEYDOWN; - - DWORD currentTick = GetTickCount(); - - // If enough time has passed between the last keypress and now, refresh the keyboard layout - if ((currentTick - lastKeyboardPressTick) > refreshKeyboardLayoutInterval) { - - // Because keyboard layouts on windows are Window-specific, to get the current - // layout we need to get the foreground window and get its layout. - - HWND hwnd = GetForegroundWindow(); - if (hwnd) { - DWORD threadID = GetWindowThreadProcessId(hwnd, NULL); - HKL newKeyboardLayout = GetKeyboardLayout(threadID); - - // It's not always valid, so update the current value only if available. - if (newKeyboardLayout != 0) { - currentKeyboardLayout = newKeyboardLayout; - } - } - - lastKeyboardPressTick = currentTick; - } - - // Get keyboard state ( necessary to decode the associated Unicode char ) - std::vector lpKeyState(256); - if (GetKeyboardState(lpKeyState.data())) { - // Convert the virtual key to an unicode char - std::array buffer; - int result = ToUnicodeEx(raw->data.keyboard.VKey, raw->data.keyboard.MakeCode, lpKeyState.data(), buffer.data(), buffer.size(), 0, currentKeyboardLayout); - - //std::cout << result << " " << buffer[0] << " " << raw->data.keyboard.VKey << std::endl; - - // We need to call the callback in two different ways based on the type of key - // The only modifier we use that has a result > 0 is the BACKSPACE, so we have to consider it. - if (result >= 1 && raw->data.keyboard.VKey != VK_BACK) { - keypress_callback(manager_instance, reinterpret_cast(buffer.data()), buffer.size(), 0, raw->data.keyboard.VKey, is_key_down); - }else{ - keypress_callback(manager_instance, nullptr, 0, 1, raw->data.keyboard.VKey, is_key_down); - } - } - } - - return 0; - } - default: - return DefWindowProc(window, msg, wp, lp); - } -} - -int32_t initialize(void * self, wchar_t * ico_path, wchar_t * bmp_path) { - manager_instance = self; - - // Load the images - g_espanso_bmp = (HBITMAP)LoadImage(NULL, bmp_path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); - g_espanso_ico = (HICON)LoadImage(NULL, ico_path, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_SHARED | LR_DEFAULTSIZE | LR_LOADFROMFILE); - - // Make the notification capable of handling different screen definitions - SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); - - // Initialize the default keyboard layout - currentKeyboardLayout = GetKeyboardLayout(0); - - // Initialize the Worker window - - // Docs: https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa - WNDCLASSEX wndclass = { - sizeof(WNDCLASSEX), // cbSize: Size of this structure - 0, // style: Class styles - window_procedure, // lpfnWndProc: Pointer to the window procedure - 0, // cbClsExtra: Number of extra bytes to allocate following the window-class structure - 0, // cbWndExtra: The number of extra bytes to allocate following the window instance. - GetModuleHandle(0), // hInstance: A handle to the instance that contains the window procedure for the class. - NULL, // hIcon: A handle to the class icon. - LoadCursor(0,IDC_ARROW), // hCursor: A handle to the class cursor. - NULL, // hbrBackground: A handle to the class background brush. - NULL, // lpszMenuName: Pointer to a null-terminated character string that specifies the resource name of the class menu - winclass, // lpszClassName: A pointer to a null-terminated string or is an atom. - NULL // hIconSm: A handle to a small icon that is associated with the window class. - }; - - // Notification Window - - // Docs: https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexa - WNDCLASSEX notificationwndclass = { - sizeof(WNDCLASSEX), // cbSize: Size of this structure - 0, // style: Class styles - window_procedure, // lpfnWndProc: Pointer to the window procedure - 0, // cbClsExtra: Number of extra bytes to allocate following the window-class structure - 0, // cbWndExtra: The number of extra bytes to allocate following the window instance. - GetModuleHandle(0), // hInstance: A handle to the instance that contains the window procedure for the class. - NULL, // hIcon: A handle to the class icon. - LoadCursor(0,IDC_ARROW), // hCursor: A handle to the class cursor. - NULL, // hbrBackground: A handle to the class background brush. - NULL, // lpszMenuName: Pointer to a null-terminated character string that specifies the resource name of the class menu - notification_winclass, // lpszClassName: A pointer to a null-terminated string or is an atom. - NULL // hIconSm: A handle to a small icon that is associated with the window class. - }; - - if (RegisterClassEx(&wndclass) && RegisterClassEx(¬ificationwndclass)) - { - // Docs: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createwindowexw - window = CreateWindowEx( - 0, // dwExStyle: The extended window style of the window being created. - winclass, // lpClassName: A null-terminated string or a class atom created by a previous call to the RegisterClass - L"Espanso Worker Window", // lpWindowName: The window name. - WS_OVERLAPPEDWINDOW, // dwStyle: The style of the window being created. - CW_USEDEFAULT, // X: The initial horizontal position of the window. - CW_USEDEFAULT, // Y: The initial vertical position of the window. - 100, // nWidth: The width, in device units, of the window. - 100, // nHeight: The height, in device units, of the window. - NULL, // hWndParent: handle to the parent or owner window of the window being created. - NULL, // hMenu: A handle to a menu, or specifies a child-window identifier, depending on the window style. - GetModuleHandle(0), // hInstance: A handle to the instance of the module to be associated with the window. - NULL // lpParam: Pointer to a value to be passed to the window - ); - - // Register raw inputs - RAWINPUTDEVICE Rid[1]; - - Rid[0].usUsagePage = 0x01; - Rid[0].usUsage = 0x06; - Rid[0].dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK; // adds HID keyboard and also ignores legacy keyboard messages - Rid[0].hwndTarget = window; - - if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) { // Something went wrong, error. - return -1; - } - - // Initialize the notification window - nw = CreateWindowEx( - WS_EX_TOOLWINDOW | WS_EX_TOPMOST, // dwExStyle: The extended window style of the window being created. - notification_winclass, // lpClassName: A null-terminated string or a class atom created by a previous call to the RegisterClass - L"Espanso Notification", // lpWindowName: The window name. - WS_POPUPWINDOW, // dwStyle: The style of the window being created. - CW_USEDEFAULT, // X: The initial horizontal position of the window. - CW_USEDEFAULT, // Y: The initial vertical position of the window. - 300, // nWidth: The width, in device units, of the window. - 100, // nHeight: The height, in device units, of the window. - NULL, // hWndParent: handle to the parent or owner window of the window being created. - NULL, // hMenu: A handle to a menu, or specifies a child-window identifier, depending on the window style. - GetModuleHandle(0), // hInstance: A handle to the instance of the module to be associated with the window. - NULL // lpParam: Pointer to a value to be passed to the window - ); - - if (nw) - { - int x, w, y, h; - y = 40; h = 30; - x = 100; w = 180; - hwnd_st_u = CreateWindowEx(0, L"static", L"ST_U", - WS_CHILD | WS_VISIBLE | WS_TABSTOP | SS_CENTER, - x, y, w, h, - nw, (HMENU)(501), - (HINSTANCE)GetWindowLong(nw, GWLP_HINSTANCE), NULL); - - SetWindowText(hwnd_st_u, L"Loading..."); - - int posX = GetSystemMetrics(SM_CXSCREEN) - 350; - int posY = GetSystemMetrics(SM_CYSCREEN) - 200; - - SetWindowPos(nw, HWND_TOP, posX, posY, 0, 0, SWP_NOSIZE); - - // Hide the window - ShowWindow(nw, SW_HIDE); - - // Setup the icon in the notification space - - SendMessage(nw, WM_SETICON, ICON_BIG, (LPARAM)g_espanso_ico); - SendMessage(nw, WM_SETICON, ICON_SMALL, (LPARAM)g_espanso_ico); - - //Notification - nid.cbSize = sizeof(nid); - nid.hWnd = nw; - nid.uID = 1; - nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; - nid.uCallbackMessage = APPWM_ICON_CLICK; - nid.hIcon = g_espanso_ico; - StringCchCopy(nid.szTip, ARRAYSIZE(nid.szTip), L"espanso"); - - // Show the notification. - Shell_NotifyIcon(NIM_ADD, &nid); - } - }else{ - // Something went wrong, error. - return -1; - } - - return 1; -} - -void eventloop() { - if (window) - { - // Hide the window - ShowWindow(window, SW_HIDE); - - // Enter the Event loop - MSG msg; - while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg); - } - - // Something went wrong, this should have been an infinite loop. -} - -/* - * Type the given string simulating keyboard presses. - */ -void send_string(const wchar_t * string) { - std::wstring msg = string; - - std::vector vec; - for (auto ch : msg) - { - INPUT input = { 0 }; - input.type = INPUT_KEYBOARD; - input.ki.dwFlags = KEYEVENTF_UNICODE; - input.ki.wScan = ch; - vec.push_back(input); - - input.ki.dwFlags |= KEYEVENTF_KEYUP; - vec.push_back(input); - } - - SendInput(vec.size(), vec.data(), sizeof(INPUT)); -} - -/* - * Send the backspace keypress, *count* times. - */ -void delete_string(int32_t count) { - std::vector vec; - - for (int i = 0; i < count; i++) { - INPUT input = { 0 }; - - input.type = INPUT_KEYBOARD; - input.ki.wScan = 0; - input.ki.time = 0; - input.ki.dwExtraInfo = 0; - input.ki.wVk = VK_BACK; - input.ki.dwFlags = 0; // 0 for key press - vec.push_back(input); - - input.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release - vec.push_back(input); - } - - SendInput(vec.size(), vec.data(), sizeof(INPUT)); -} - -void send_vkey(int32_t vk) { - std::vector vec; - - INPUT input = { 0 }; - - input.type = INPUT_KEYBOARD; - input.ki.wScan = 0; - input.ki.time = 0; - input.ki.dwExtraInfo = 0; - input.ki.wVk = vk; - input.ki.dwFlags = 0; // 0 for key press - vec.push_back(input); - - input.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release - vec.push_back(input); - - SendInput(vec.size(), vec.data(), sizeof(INPUT)); -} - -void trigger_paste() { - std::vector vec; - - INPUT input = { 0 }; - - input.type = INPUT_KEYBOARD; - input.ki.wScan = 0; - input.ki.time = 0; - input.ki.dwExtraInfo = 0; - input.ki.wVk = VK_CONTROL; - input.ki.dwFlags = 0; // 0 for key press - vec.push_back(input); - - input.ki.wVk = 0x56; // V KEY - vec.push_back(input); - - input.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release - vec.push_back(input); - - input.ki.wVk = VK_CONTROL; - vec.push_back(input); - - SendInput(vec.size(), vec.data(), sizeof(INPUT)); -} - - -// SYSTEM - -int32_t get_active_window_name(wchar_t * buffer, int32_t size) { - HWND hwnd = GetForegroundWindow(); - - return GetWindowText(hwnd, buffer, size); -} - -int32_t get_active_window_executable(wchar_t * buffer, int32_t size) { - HWND hwnd = GetForegroundWindow(); - - // Extract the window PID - DWORD windowPid; - GetWindowThreadProcessId(hwnd, &windowPid); - - DWORD dsize = (DWORD) size; - - // Extract the process executable file path - HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, windowPid); - int res = QueryFullProcessImageNameW(process, 0, buffer, &dsize); - CloseHandle(process); - - return res; -} - -// Notifications - -int32_t show_notification(wchar_t * message) { - if (nw != NULL) { - wchar_t * buffer = new wchar_t[100]; - swprintf(buffer, 100, L"%ls", message); - - PostMessage(nw, APPWM_NOTIFICATION_POPUP, reinterpret_cast(buffer), 0); - return 1; - } - - return -1; -} - -void close_notification() { - if (nw != NULL) { - PostMessage(nw, APPWM_NOTIFICATION_CLOSE, 0, 0); - } -} - -int32_t show_context_menu(MenuItem * items, int32_t count) { - if (nw != NULL) { - MenuItem * items_buffer = new MenuItem[count]; - memcpy(items_buffer, items, sizeof(MenuItem)*count); - - PostMessage(nw, APPWM_SHOW_CONTEXT_MENU, reinterpret_cast(items_buffer), static_cast(count)); - return 1; - } - - return -1; -} - -void cleanup_ui() { - Shell_NotifyIcon(NIM_DELETE, &nid); -} - -// SYSTEM - -int32_t start_daemon_process() { - wchar_t cmd[MAX_PATH]; - swprintf(cmd, MAX_PATH, L"espanso.exe daemon"); - - // Get current espanso directory - TCHAR espansoFilePath[MAX_PATH]; - GetModuleFileName(NULL, espansoFilePath, MAX_PATH); - - STARTUPINFO si = { sizeof(si) }; - PROCESS_INFORMATION pi; - - // Documentation: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw - BOOL res = CreateProcess( - espansoFilePath, - cmd, - NULL, - NULL, - FALSE, - DETACHED_PROCESS, - NULL, - NULL, - &si, - &pi - ); - - if (!res) { - return -1; - } - - return 1; -} - -// CLIPBOARD - -int32_t set_clipboard(wchar_t *text) { - const size_t len = wcslen(text) + 1; - HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len * sizeof(wchar_t)); - memcpy(GlobalLock(hMem), text, len * sizeof(wchar_t)); - GlobalUnlock(hMem); - if (!OpenClipboard(NULL)) { - return -1; - } - EmptyClipboard(); - if (!SetClipboardData(CF_UNICODETEXT, hMem)) { - return -2; - } - CloseClipboard(); -} - -int32_t get_clipboard(wchar_t *buffer, int32_t size) { - if (!OpenClipboard(NULL)) { - return -1; - } - - // Get handle of clipboard object for ANSI text - HANDLE hData = GetClipboardData(CF_UNICODETEXT); - if (!hData) { - return -2; - } - - HGLOBAL hMem = GlobalLock(hData); - if (!hMem) { - return -3; - } - - GlobalUnlock(hMem); - - swprintf(buffer, size, L"%s", hMem); - - CloseClipboard(); -} diff --git a/native/libwinbridge/bridge.h b/native/libwinbridge/bridge.h deleted file mode 100644 index e9ddbf8..0000000 --- a/native/libwinbridge/bridge.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#ifndef ESPANSO_BRIDGE_H -#define ESPANSO_BRIDGE_H - -#include -#include - -// SYSTEM - -extern "C" int32_t start_daemon_process(); - -extern void * manager_instance; - -/* - * Initialize the Windows parameters - * return: 1 if OK, -1 otherwise. - */ -extern "C" int32_t initialize(void * self, wchar_t * ico_path, wchar_t * bmp_path); - -/* - * Called when a new keypress is made, the first argument is an int array, - * while the second is the size of the array. - */ -typedef void (*KeypressCallback)(void * self, int32_t *buffer, int32_t len, int32_t is_modifier, int32_t key_code, int32_t is_key_down); -extern KeypressCallback keypress_callback; - -/* - * Register the callback that will be called when a keypress was made - */ -extern "C" void register_keypress_callback(KeypressCallback callback); - -/* - * Start the event loop indefinitely. Blocking call. - */ -extern "C" void eventloop(); - -// Keyboard Manager - -/* - * Type the given string by simulating Key Presses - */ -extern "C" void send_string(const wchar_t * string); - -/* - * Send the given Virtual Key press - */ -extern "C" void send_vkey(int32_t vk); - -/* - * Send the backspace keypress, *count* times. - */ -extern "C" void delete_string(int32_t count); - -/* - * Send the Paste keyboard shortcut (CTRL+V) - */ -extern "C" void trigger_paste(); - -// Detect current application commands - -/* - * Return the active windows's title - */ -extern "C" int32_t get_active_window_name(wchar_t * buffer, int32_t size); - -/* - * Return the active windows's executable path - */ -extern "C" int32_t get_active_window_executable(wchar_t * buffer, int32_t size); - -// UI - -/* - * Called when the tray icon is clicked - */ -typedef void (*IconClickCallback)(void * self); -extern IconClickCallback icon_click_callback; -extern "C" void register_icon_click_callback(IconClickCallback callback); - -// CONTEXT MENU - -typedef struct { - int32_t id; - int32_t type; - wchar_t name[100]; -} MenuItem; - -extern "C" int32_t show_context_menu(MenuItem * items, int32_t count); - -/* - * Called when the context menu is clicked - */ -typedef void (*ContextMenuClickCallback)(void * self, int32_t id); -extern ContextMenuClickCallback context_menu_click_callback; -extern "C" void register_context_menu_click_callback(ContextMenuClickCallback callback); - -/* - * Hide the tray icon - */ -extern "C" void cleanup_ui(); - -// NOTIFICATION - -/* - * Show a window containing the notification. - */ -extern "C" int32_t show_notification(wchar_t * message); - -/* - * Close the notification if present - */ -extern "C" void close_notification(); - -// CLIPBOARD - -/* - * Return the clipboard text - */ -extern "C" int32_t get_clipboard(wchar_t * buffer, int32_t size); - -/* - * Set the clipboard text - */ -extern "C" int32_t set_clipboard(wchar_t * text); - -#endif //ESPANSO_BRIDGE_H \ No newline at end of file diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.pbxproj b/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.pbxproj deleted file mode 100644 index a3fa5be..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.pbxproj +++ /dev/null @@ -1,312 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 50; - objects = { - -/* Begin PBXBuildFile section */ - B6F9DF16232283F8005233EB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B6F9DF15232283F8005233EB /* AppDelegate.m */; }; - B6F9DF18232283F8005233EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B6F9DF17232283F8005233EB /* Assets.xcassets */; }; - B6F9DF1E232283F8005233EB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B6F9DF1D232283F8005233EB /* main.m */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - B6F9DF11232283F8005233EB /* EspansoNotifyHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EspansoNotifyHelper.app; sourceTree = BUILT_PRODUCTS_DIR; }; - B6F9DF14232283F8005233EB /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - B6F9DF15232283F8005233EB /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - B6F9DF17232283F8005233EB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - B6F9DF1C232283F8005233EB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - B6F9DF1D232283F8005233EB /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - B6F9DF1F232283F8005233EB /* EspansoNotifyHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EspansoNotifyHelper.entitlements; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - B6F9DF0E232283F8005233EB /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - B6F9DF08232283F8005233EB = { - isa = PBXGroup; - children = ( - B6F9DF13232283F8005233EB /* EspansoNotifyHelper */, - B6F9DF12232283F8005233EB /* Products */, - ); - sourceTree = ""; - }; - B6F9DF12232283F8005233EB /* Products */ = { - isa = PBXGroup; - children = ( - B6F9DF11232283F8005233EB /* EspansoNotifyHelper.app */, - ); - name = Products; - sourceTree = ""; - }; - B6F9DF13232283F8005233EB /* EspansoNotifyHelper */ = { - isa = PBXGroup; - children = ( - B6F9DF14232283F8005233EB /* AppDelegate.h */, - B6F9DF15232283F8005233EB /* AppDelegate.m */, - B6F9DF17232283F8005233EB /* Assets.xcassets */, - B6F9DF1C232283F8005233EB /* Info.plist */, - B6F9DF1D232283F8005233EB /* main.m */, - B6F9DF1F232283F8005233EB /* EspansoNotifyHelper.entitlements */, - ); - path = EspansoNotifyHelper; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - B6F9DF10232283F8005233EB /* EspansoNotifyHelper */ = { - isa = PBXNativeTarget; - buildConfigurationList = B6F9DF22232283F8005233EB /* Build configuration list for PBXNativeTarget "EspansoNotifyHelper" */; - buildPhases = ( - B6F9DF0D232283F8005233EB /* Sources */, - B6F9DF0E232283F8005233EB /* Frameworks */, - B6F9DF0F232283F8005233EB /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = EspansoNotifyHelper; - productName = EspansoNotifyHelper; - productReference = B6F9DF11232283F8005233EB /* EspansoNotifyHelper.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - B6F9DF09232283F8005233EB /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1010; - ORGANIZATIONNAME = "Federico Terzi"; - TargetAttributes = { - B6F9DF10232283F8005233EB = { - CreatedOnToolsVersion = 10.1; - }; - }; - }; - buildConfigurationList = B6F9DF0C232283F8005233EB /* Build configuration list for PBXProject "EspansoNotifyHelper" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = B6F9DF08232283F8005233EB; - productRefGroup = B6F9DF12232283F8005233EB /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - B6F9DF10232283F8005233EB /* EspansoNotifyHelper */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - B6F9DF0F232283F8005233EB /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - B6F9DF18232283F8005233EB /* Assets.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - B6F9DF0D232283F8005233EB /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - B6F9DF1E232283F8005233EB /* main.m in Sources */, - B6F9DF16232283F8005233EB /* AppDelegate.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - B6F9DF20232283F8005233EB /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "Mac Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - }; - name = Debug; - }; - B6F9DF21232283F8005233EB /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "Mac Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = macosx; - }; - name = Release; - }; - B6F9DF23232283F8005233EB /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = EspansoNotifyHelper/EspansoNotifyHelper.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = N69XJWRM3X; - INFOPLIST_FILE = EspansoNotifyHelper/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.federicoterzi.EspansoNotifyHelper; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - B6F9DF24232283F8005233EB /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = EspansoNotifyHelper/EspansoNotifyHelper.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = N69XJWRM3X; - INFOPLIST_FILE = EspansoNotifyHelper/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.federicoterzi.EspansoNotifyHelper; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - B6F9DF0C232283F8005233EB /* Build configuration list for PBXProject "EspansoNotifyHelper" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - B6F9DF20232283F8005233EB /* Debug */, - B6F9DF21232283F8005233EB /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - B6F9DF22232283F8005233EB /* Build configuration list for PBXNativeTarget "EspansoNotifyHelper" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - B6F9DF23232283F8005233EB /* Debug */, - B6F9DF24232283F8005233EB /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = B6F9DF09232283F8005233EB /* Project object */; -} diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index b73ee34..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.xcworkspace/xcuserdata/freddy.xcuserdatad/UserInterfaceState.xcuserstate b/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.xcworkspace/xcuserdata/freddy.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 84373c4..0000000 Binary files a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/project.xcworkspace/xcuserdata/freddy.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/xcshareddata/xcschemes/EspansoNotifyHelper.xcscheme b/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/xcshareddata/xcschemes/EspansoNotifyHelper.xcscheme deleted file mode 100644 index 69a385d..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/xcshareddata/xcschemes/EspansoNotifyHelper.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/xcuserdata/freddy.xcuserdatad/xcschemes/xcschememanagement.plist b/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/xcuserdata/freddy.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 396e625..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper.xcodeproj/xcuserdata/freddy.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - EspansoNotifyHelper.xcscheme_^#shared#^_ - - orderHint - 0 - - - SuppressBuildableAutocreation - - B6F9DF10232283F8005233EB - - primary - - - - - diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/AppDelegate.h b/other/EspansoNotifyHelper/EspansoNotifyHelper/AppDelegate.h deleted file mode 100644 index dbe09df..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper/AppDelegate.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#import - -@interface AppDelegate : NSObject - - -@end - diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/AppDelegate.m b/other/EspansoNotifyHelper/EspansoNotifyHelper/AppDelegate.m deleted file mode 100644 index b076bcb..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper/AppDelegate.m +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#import "AppDelegate.h" - -@interface AppDelegate () - -@property (weak) IBOutlet NSWindow *window; -@end - -@implementation AppDelegate - -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self]; - - NSArray *args = [[NSProcessInfo processInfo] arguments]; - - NSString *title = @"Title"; - NSString *desc = @"Description"; - double delay = 1.5; - - if ([args count] > 3) { - title = args[1]; - desc = args[2]; - delay = [args[3] doubleValue]; - } - - NSUserNotification *notification = [[NSUserNotification alloc] init]; - notification.title = title; - notification.informativeText = desc; - notification.soundName = nil; - - [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; - - [[NSUserNotificationCenter defaultUserNotificationCenter] performSelector:@selector(removeDeliveredNotification:) withObject:notification afterDelay:delay]; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - NSRunningApplication *app = [NSRunningApplication currentApplication]; - [app terminate]; - }); -} - - -- (void)applicationWillTerminate:(NSNotification *)aNotification { - // Insert code here to tear down your application -} - -- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification{ - return YES; -} - - -@end diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/Contents.json b/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index ce3f357..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "icongreen-16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "icongreen-32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "icongreen-32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "icongreen-64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "icongreen-128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "icongreen-256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "icongreen-256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "icongreen-512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "icongreen-512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "icongreen-1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-1024.png b/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-1024.png deleted file mode 100644 index 3f2555a..0000000 Binary files a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-1024.png and /dev/null differ diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-128.png b/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-128.png deleted file mode 100644 index 181c5e8..0000000 Binary files a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-128.png and /dev/null differ diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-16.png b/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-16.png deleted file mode 100644 index 355addc..0000000 Binary files a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-16.png and /dev/null differ diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-256.png b/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-256.png deleted file mode 100644 index 7423ef9..0000000 Binary files a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-256.png and /dev/null differ diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-32.png b/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-32.png deleted file mode 100644 index 520331d..0000000 Binary files a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-32.png and /dev/null differ diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-512.png b/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-512.png deleted file mode 100644 index 4bf1365..0000000 Binary files a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-512.png and /dev/null differ diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-64.png b/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-64.png deleted file mode 100644 index e5809ef..0000000 Binary files a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/AppIcon.appiconset/icongreen-64.png and /dev/null differ diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/Contents.json b/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/EspansoNotifyHelper.entitlements b/other/EspansoNotifyHelper/EspansoNotifyHelper/EspansoNotifyHelper.entitlements deleted file mode 100644 index f2ef3ae..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper/EspansoNotifyHelper.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.files.user-selected.read-only - - - diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/Info.plist b/other/EspansoNotifyHelper/EspansoNotifyHelper/Info.plist deleted file mode 100644 index 6b44964..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSApplicationCategoryType - public.app-category.utilities - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright Β© 2019 Federico Terzi. All rights reserved. - NSMainNibFile - MainMenu - LSUIElement - - NSPrincipalClass - NSApplication - - diff --git a/other/EspansoNotifyHelper/EspansoNotifyHelper/main.m b/other/EspansoNotifyHelper/EspansoNotifyHelper/main.m deleted file mode 100644 index 68731bb..0000000 --- a/other/EspansoNotifyHelper/EspansoNotifyHelper/main.m +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#import -#import "AppDelegate.h" - -int main(int argc, const char * argv[]) { - AppDelegate *delegate = [[AppDelegate alloc] init]; - NSApplication * application = [NSApplication sharedApplication]; - [application setDelegate:delegate]; - [NSApp run]; - - return 0; -} diff --git a/packager.py b/packager.py deleted file mode 100644 index 03e6510..0000000 --- a/packager.py +++ /dev/null @@ -1,156 +0,0 @@ -import subprocess -import sys -import os -import platform -import hashlib -import click -import shutil -import toml -from dataclasses import dataclass - -PACKAGER_TARGET_DIR = "target/packager" - -@dataclass -class PackageInfo: - name: str - version: str - description: str - publisher: str - url: str - -@click.group() -def cli(): - pass - -@cli.command() -@click.option('--skipcargo', default=False, is_flag=True, help="Skip cargo release build") -def build(skipcargo): - """Build espanso distribution""" - # Check operating system - TARGET_OS = "macos" - if platform.system() == "Windows": - TARGET_OS = "windows" - elif platform.system() == "Linux": - TARGET_OS = "linux" - - print("Detected OS:", TARGET_OS) - - print("Loading info from Cargo.toml") - cargo_info = toml.load("Cargo.toml") - package_info = PackageInfo(cargo_info["package"]["name"], - cargo_info["package"]["version"], - cargo_info["package"]["description"], - cargo_info["package"]["authors"][0], - cargo_info["package"]["homepage"]) - print(package_info) - - if not skipcargo: - print("Building release version...") - subprocess.run(["cargo", "build", "--release"]) - else: - print("Skipping build") - - if TARGET_OS == "windows": - build_windows(package_info) - elif TARGET_OS == "macos": - build_mac(package_info) - - -def build_windows(package_info): - print("Starting packaging process for Windows...") - - # Check Inno Setup - try: - subprocess.run(["iscc"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except FileNotFoundError: - raise Exception("Could not find Inno Setup compiler. Please install it from here: http://www.jrsoftware.org/isdl.php") - - print("Clearing target dirs") - - # Clearing previous build directory - if os.path.isdir(PACKAGER_TARGET_DIR): - print("Cleaning packager temp directory...") - shutil.rmtree(PACKAGER_TARGET_DIR) - - TARGET_DIR = os.path.join(PACKAGER_TARGET_DIR, "win") - os.makedirs(TARGET_DIR, exist_ok=True) - - INSTALLER_NAME = f"espanso-win-installer" - - # Inno setup - shutil.copy("packager/win/modpath.iss", os.path.join(TARGET_DIR, "modpath.iss")) - - print("Processing inno setup template") - with open("packager/win/setupscript.iss", "r") as iss_script: - content = iss_script.read() - - # Replace variables - content = content.replace("{{{app_name}}}", package_info.name) - content = content.replace("{{{app_version}}}", package_info.version) - content = content.replace("{{{app_publisher}}}", package_info.publisher) - content = content.replace("{{{app_url}}}", package_info.url) - content = content.replace("{{{app_license}}}", os.path.abspath("LICENSE")) - content = content.replace("{{{app_icon}}}", os.path.abspath("packager/win/icon.ico")) - content = content.replace("{{{executable_path}}}", os.path.abspath("target/release/espanso.exe")) - content = content.replace("{{{output_dir}}}", os.path.abspath(TARGET_DIR)) - content = content.replace("{{{output_name}}}", INSTALLER_NAME) - - with open(os.path.join(TARGET_DIR, "setupscript.iss"), "w") as output_script: - output_script.write(content) - - print("Compiling installer with Inno setup") - subprocess.run(["iscc", os.path.abspath(os.path.join(TARGET_DIR, "setupscript.iss"))]) - - -def build_mac(package_info): - print("Starting packaging process for MacOS...") - - print("Clearing target dirs") - - # Clearing previous build directory - if os.path.isdir(PACKAGER_TARGET_DIR): - print("Cleaning packager temp directory...") - shutil.rmtree(PACKAGER_TARGET_DIR) - - TARGET_DIR = os.path.join(PACKAGER_TARGET_DIR, "mac") - os.makedirs(TARGET_DIR, exist_ok=True) - - print("Compressing release to archive...") - target_name = f"espanso-mac.tar.gz" - archive_target = os.path.abspath(os.path.join(TARGET_DIR, target_name)) - subprocess.run(["tar", - "-C", os.path.abspath("target/release"), - "-cvf", - archive_target, - "espanso", - ]) - print(f"Created archive: {archive_target}") - - print("Processing Homebrew formula template") - with open("packager/mac/espanso.rb", "r") as formula_template: - content = formula_template.read() - - # Replace variables - content = content.replace("{{{app_desc}}}", package_info.description) - content = content.replace("{{{app_url}}}", package_info.url) - content = content.replace("{{{app_version}}}", package_info.version) - - # Calculate hash - with open(archive_target, "rb") as f: - bytes = f.read() - readable_hash = hashlib.sha256(bytes).hexdigest() - content = content.replace("{{{release_hash}}}", readable_hash) - - with open(os.path.join(TARGET_DIR, "espanso.rb"), "w") as output_script: - output_script.write(content) - - print("Done!") - -if __name__ == '__main__': - print("[[ espanso packager ]]") - - # Check python version 3 - if sys.version_info[0] < 3: - raise Exception("Must be using Python 3") - - cli() \ No newline at end of file diff --git a/packager/mac/espanso.rb b/packager/mac/espanso.rb deleted file mode 100644 index 6e7f477..0000000 --- a/packager/mac/espanso.rb +++ /dev/null @@ -1,14 +0,0 @@ -# Documentation: https://docs.brew.sh/Formula-Cookbook -# https://rubydoc.brew.sh/Formula -# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST! -class Espanso < Formula - desc "{{{app_desc}}}" - homepage "{{{app_url}}}" - url "https://github.com/federico-terzi/espanso/releases/latest/download/espanso-mac.tar.gz" - sha256 "{{{release_hash}}}" - version "{{{app_version}}}" - - def install - bin.install "espanso" - end -end \ No newline at end of file diff --git a/packager/win/icon.ico b/packager/win/icon.ico deleted file mode 100644 index 1d1c06c..0000000 Binary files a/packager/win/icon.ico and /dev/null differ diff --git a/packager/win/modpath.iss b/packager/win/modpath.iss deleted file mode 100644 index c55ec60..0000000 --- a/packager/win/modpath.iss +++ /dev/null @@ -1,219 +0,0 @@ -// ---------------------------------------------------------------------------- -// -// Inno Setup Ver: 5.4.2 -// Script Version: 1.4.2 -// Author: Jared Breland -// Homepage: http://www.legroom.net/software -// License: GNU Lesser General Public License (LGPL), version 3 -// http://www.gnu.org/licenses/lgpl.html -// -// Script Function: -// Allow modification of environmental path directly from Inno Setup installers -// -// Instructions: -// Copy modpath.iss to the same directory as your setup script -// -// Add this statement to your [Setup] section -// ChangesEnvironment=true -// -// Add this statement to your [Tasks] section -// You can change the Description or Flags -// You can change the Name, but it must match the ModPathName setting below -// Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked -// -// Add the following to the end of your [Code] section -// ModPathName defines the name of the task defined above -// ModPathType defines whether the 'user' or 'system' path will be modified; -// this will default to user if anything other than system is set -// setArrayLength must specify the total number of dirs to be added -// Result[0] contains first directory, Result[1] contains second, etc. -// const -// ModPathName = 'modifypath'; -// ModPathType = 'user'; -// -// function ModPathDir(): TArrayOfString; -// begin -// setArrayLength(Result, 1); -// Result[0] := ExpandConstant('{app}'); -// end; -// #include "modpath.iss" -// ---------------------------------------------------------------------------- - -procedure ModPath(); -var - oldpath: String; - newpath: String; - updatepath: Boolean; - pathArr: TArrayOfString; - aExecFile: String; - aExecArr: TArrayOfString; - i, d: Integer; - pathdir: TArrayOfString; - regroot: Integer; - regpath: String; - -begin - // Get constants from main script and adjust behavior accordingly - // ModPathType MUST be 'system' or 'user'; force 'user' if invalid - if ModPathType = 'system' then begin - regroot := HKEY_LOCAL_MACHINE; - regpath := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'; - end else begin - regroot := HKEY_CURRENT_USER; - regpath := 'Environment'; - end; - - // Get array of new directories and act on each individually - pathdir := ModPathDir(); - for d := 0 to GetArrayLength(pathdir)-1 do begin - updatepath := true; - - // Modify WinNT path - if UsingWinNT() = true then begin - - // Get current path, split into an array - RegQueryStringValue(regroot, regpath, 'Path', oldpath); - oldpath := oldpath + ';'; - i := 0; - - while (Pos(';', oldpath) > 0) do begin - SetArrayLength(pathArr, i+1); - pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1); - oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath)); - i := i + 1; - - // Check if current directory matches app dir - if pathdir[d] = pathArr[i-1] then begin - // if uninstalling, remove dir from path - if IsUninstaller() = true then begin - continue; - // if installing, flag that dir already exists in path - end else begin - updatepath := false; - end; - end; - - // Add current directory to new path - if i = 1 then begin - newpath := pathArr[i-1]; - end else begin - newpath := newpath + ';' + pathArr[i-1]; - end; - end; - - // Append app dir to path if not already included - if (IsUninstaller() = false) AND (updatepath = true) then - newpath := newpath + ';' + pathdir[d]; - - // Write new path - RegWriteStringValue(regroot, regpath, 'Path', newpath); - - // Modify Win9x path - end else begin - - // Convert to shortened dirname - pathdir[d] := GetShortName(pathdir[d]); - - // If autoexec.bat exists, check if app dir already exists in path - aExecFile := 'C:\AUTOEXEC.BAT'; - if FileExists(aExecFile) then begin - LoadStringsFromFile(aExecFile, aExecArr); - for i := 0 to GetArrayLength(aExecArr)-1 do begin - if IsUninstaller() = false then begin - // If app dir already exists while installing, skip add - if (Pos(pathdir[d], aExecArr[i]) > 0) then - updatepath := false; - break; - end else begin - // If app dir exists and = what we originally set, then delete at uninstall - if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then - aExecArr[i] := ''; - end; - end; - end; - - // If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path - if (IsUninstaller() = false) AND (updatepath = true) then begin - SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True); - - // If uninstalling, write the full autoexec out - end else begin - SaveStringsToFile(aExecFile, aExecArr, False); - end; - end; - end; -end; - -// Split a string into an array using passed delimeter -procedure MPExplode(var Dest: TArrayOfString; Text: String; Separator: String); -var - i: Integer; -begin - i := 0; - repeat - SetArrayLength(Dest, i+1); - if Pos(Separator,Text) > 0 then begin - Dest[i] := Copy(Text, 1, Pos(Separator, Text)-1); - Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text)); - i := i + 1; - end else begin - Dest[i] := Text; - Text := ''; - end; - until Length(Text)=0; -end; - - -procedure CurStepChanged(CurStep: TSetupStep); -var - taskname: String; -begin - taskname := ModPathName; - if CurStep = ssPostInstall then - if IsTaskSelected(taskname) then - ModPath(); -end; - -procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); -var - aSelectedTasks: TArrayOfString; - i: Integer; - taskname: String; - regpath: String; - regstring: String; - appid: String; -begin - // only run during actual uninstall - if CurUninstallStep = usUninstall then begin - // get list of selected tasks saved in registry at install time - appid := '{#emit SetupSetting("AppId")}'; - if appid = '' then appid := '{#emit SetupSetting("AppName")}'; - regpath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+appid+'_is1'); - RegQueryStringValue(HKLM, regpath, 'Inno Setup: Selected Tasks', regstring); - if regstring = '' then RegQueryStringValue(HKCU, regpath, 'Inno Setup: Selected Tasks', regstring); - - // check each task; if matches modpath taskname, trigger patch removal - if regstring <> '' then begin - taskname := ModPathName; - MPExplode(aSelectedTasks, regstring, ','); - if GetArrayLength(aSelectedTasks) > 0 then begin - for i := 0 to GetArrayLength(aSelectedTasks)-1 do begin - if comparetext(aSelectedTasks[i], taskname) = 0 then - ModPath(); - end; - end; - end; - end; -end; - -function NeedRestart(): Boolean; -var - taskname: String; -begin - taskname := ModPathName; - if IsTaskSelected(taskname) and not UsingWinNT() then begin - Result := True; - end else begin - Result := False; - end; -end; diff --git a/packager/win/setupscript.iss b/packager/win/setupscript.iss deleted file mode 100644 index 6e3ff13..0000000 --- a/packager/win/setupscript.iss +++ /dev/null @@ -1,66 +0,0 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -#define MyAppName "{{{app_name}}}" -#define MyAppVersion "{{{app_version}}}" -#define MyAppPublisher "{{{app_publisher}}}" -#define MyAppURL "{{{app_url}}}" -#define MyAppExeName "espanso.exe" - -[Setup] -; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. -; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{0E3D83CE-A644-4E0E-8487-657C7ECF6BF9} -AppName={#MyAppName} -AppVersion={#MyAppVersion} -;AppVerName={#MyAppName} {#MyAppVersion} -AppPublisher={#MyAppPublisher} -AppPublisherURL={#MyAppURL} -AppSupportURL={#MyAppURL} -AppUpdatesURL={#MyAppURL} -DefaultDirName={autopf}\{#MyAppName} -DisableProgramGroupPage=yes -LicenseFile="{{{app_license}}}" -; Remove the following line to run in administrative install mode (install for all users.) -PrivilegesRequired=lowest -OutputDir="{{{output_dir}}}" -OutputBaseFilename={{{output_name}}} -SetupIconFile="{{{app_icon}}}" -Compression=lzma -SolidCompression=yes -WizardStyle=modern -ChangesEnvironment=yes - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Files] -Source: "{{{executable_path}}}"; DestDir: "{app}"; Flags: ignoreversion -Source: "{{{app_icon}}}"; DestDir: "{app}"; Flags: ignoreversion -; NOTE: Don't use "Flags: ignoreversion" on any shared system files - -[Icons] -Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\icon.ico" -Name: "{userstartup}\espanso"; Filename: "{app}\espanso.exe"; Tasks:StartMenuEntry; - -[Tasks] -Name: modifypath; Description: Add espanso to PATH ( recommended ); -Name: "StartMenuEntry" ; Description: "Start espanso at Windows startup" ; - -[Code] -const - ModPathName = 'modifypath'; - ModPathType = 'user'; - -function ModPathDir(): TArrayOfString; -begin - setArrayLength(Result, 1) - Result[0] := ExpandConstant('{app}'); -end; -#include "modpath.iss" - -[Run] -Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent - -[UninstallRun] -Filename: "{cmd}"; Parameters: "/C ""taskkill /im espanso.exe /f /t" \ No newline at end of file diff --git a/src/bridge/linux.rs b/src/bridge/linux.rs deleted file mode 100644 index a7f40e3..0000000 --- a/src/bridge/linux.rs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::os::raw::{c_void, c_char}; - -#[allow(improper_ctypes)] -#[link(name="linuxbridge", kind="static")] -extern { - pub fn initialize(s: *const c_void) -> i32; - pub fn eventloop(); - pub fn cleanup(); - - // System - pub fn get_active_window_name(buffer: *mut c_char, size: i32) -> i32; - pub fn get_active_window_class(buffer: *mut c_char, size: i32) -> i32; - pub fn get_active_window_executable(buffer: *mut c_char, size: i32) -> i32; - pub fn is_current_window_terminal() -> i32; - - // Keyboard - pub fn register_keypress_callback(cb: extern fn(_self: *mut c_void, *const u8, - i32, i32, i32)); - - pub fn send_string(string: *const c_char); - pub fn delete_string(count: i32); - pub fn trigger_paste(); - pub fn trigger_terminal_paste(); -} \ No newline at end of file diff --git a/src/bridge/macos.rs b/src/bridge/macos.rs deleted file mode 100644 index 830e994..0000000 --- a/src/bridge/macos.rs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::os::raw::{c_void, c_char}; - -#[repr(C)] -pub struct MacMenuItem { - pub item_id: i32, - pub item_type: i32, - pub item_name: [c_char; 100], -} - -#[allow(improper_ctypes)] -#[link(name="macbridge", kind="static")] -extern { - pub fn initialize(s: *const c_void, icon_path: *const c_char); - pub fn eventloop(); - - // System - pub fn check_accessibility() -> i32; - pub fn prompt_accessibility() -> i32; - pub fn open_settings_panel(); - pub fn get_active_app_bundle(buffer: *mut c_char, size: i32) -> i32; - pub fn get_active_app_identifier(buffer: *mut c_char, size: i32) -> i32; - - // Clipboard - pub fn get_clipboard(buffer: *mut c_char, size: i32) -> i32; - pub fn set_clipboard(text: *const c_char) -> i32; - - // UI - pub fn register_icon_click_callback(cb: extern fn(_self: *mut c_void)); - pub fn show_context_menu(items: *const MacMenuItem, count: i32) -> i32; - pub fn register_context_menu_click_callback(cb: extern fn(_self: *mut c_void, id: i32)); - - // Keyboard - pub fn register_keypress_callback(cb: extern fn(_self: *mut c_void, *const u8, - i32, i32, i32)); - - pub fn send_string(string: *const c_char); - pub fn send_vkey(vk: i32); - pub fn delete_string(count: i32); - pub fn trigger_paste(); -} \ No newline at end of file diff --git a/src/bridge/mod.rs b/src/bridge/mod.rs deleted file mode 100644 index 3c6b412..0000000 --- a/src/bridge/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#[cfg(target_os = "windows")] -pub(crate) mod windows; - -#[cfg(target_os = "linux")] -pub(crate) mod linux; - -#[cfg(target_os = "macos")] -pub(crate) mod macos; \ No newline at end of file diff --git a/src/bridge/windows.rs b/src/bridge/windows.rs deleted file mode 100644 index 6866cbe..0000000 --- a/src/bridge/windows.rs +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::os::raw::{c_void}; - -#[repr(C)] -pub struct WindowsMenuItem { - pub item_id: i32, - pub item_type: i32, - pub item_name: [u16; 100], -} - -#[allow(improper_ctypes)] -#[link(name="winbridge", kind="static")] -extern { - pub fn start_daemon_process() -> i32; - pub fn initialize(s: *const c_void, ico_path: *const u16, bmp_path: *const u16) -> i32; - - // SYSTEM - pub fn get_active_window_name(buffer: *mut u16, size: i32) -> i32; - pub fn get_active_window_executable(buffer: *mut u16, size: i32) -> i32; - - // UI - pub fn show_notification(message: *const u16) -> i32; - pub fn close_notification(); - pub fn show_context_menu(items: *const WindowsMenuItem, count: i32) -> i32; - pub fn register_icon_click_callback(cb: extern fn(_self: *mut c_void)); - pub fn register_context_menu_click_callback(cb: extern fn(_self: *mut c_void, id: i32)); - pub fn cleanup_ui(); - - // CLIPBOARD - pub fn get_clipboard(buffer: *mut u16, size: i32) -> i32; - pub fn set_clipboard(payload: *const u16) -> i32; - - // KEYBOARD - pub fn register_keypress_callback(cb: extern fn(_self: *mut c_void, *const i32, - i32, i32, i32, i32)); - - pub fn eventloop(); - pub fn send_string(string: *const u16); - pub fn send_vkey(vk: i32); - pub fn delete_string(count: i32); - pub fn trigger_paste(); -} \ No newline at end of file diff --git a/src/check.rs b/src/check.rs deleted file mode 100644 index 34b4f80..0000000 --- a/src/check.rs +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -// This functions are used to check if the required dependencies are satisfied -// before starting espanso - -#[cfg(target_os = "linux")] -pub fn check_dependencies() -> bool { - use std::process::Command; - - let mut result = true; - - // Make sure notify-send is installed - let status = Command::new("notify-send") - .arg("-v") - .output(); - if let Err(_) = status { - println!("Error: 'notify-send' command is needed for espanso to work correctly, please install it."); - result = false; - } - - // Make sure xclip is installed - let status = Command::new("xclip") - .arg("-version") - .output(); - if let Err(_) = status { - println!("Error: 'xclip' command is needed for espanso to work correctly, please install it."); - result = false; - } - - result -} - -#[cfg(target_os = "macos")] -pub fn check_dependencies() -> bool { - // Nothing to do here - true -} - -#[cfg(target_os = "windows")] -pub fn check_dependencies() -> bool { - // Nothing needed on windows - true -} \ No newline at end of file diff --git a/src/clipboard/linux.rs b/src/clipboard/linux.rs deleted file mode 100644 index a20c2c6..0000000 --- a/src/clipboard/linux.rs +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::process::{Command, Stdio}; -use std::io::{Write}; -use log::error; - -pub struct LinuxClipboardManager {} - -impl super::ClipboardManager for LinuxClipboardManager { - fn get_clipboard(&self) -> Option { - let res = Command::new("xclip") - .args(&["-o", "-sel", "clip"]) - .output(); - - if let Ok(output) = res { - if output.status.success() { - let s = String::from_utf8_lossy(&output.stdout); - return Some((*s).to_owned()); - } - } - - None - } - - fn set_clipboard(&self, payload: &str) { - let res = Command::new("xclip") - .args(&["-sel", "clip"]) - .stdin(Stdio::piped()) - .spawn(); - - if let Ok(mut child) = res { - let stdin = child.stdin.as_mut(); - - if let Some(output) = stdin { - let res = output.write_all(payload.as_bytes()); - - if let Err(e) = res { - error!("Could not set clipboard: {}", e); - } - } - } - } -} - -impl LinuxClipboardManager { - pub fn new() -> LinuxClipboardManager { - LinuxClipboardManager{} - } -} \ No newline at end of file diff --git a/src/clipboard/macos.rs b/src/clipboard/macos.rs deleted file mode 100644 index 65c10bf..0000000 --- a/src/clipboard/macos.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::os::raw::c_char; -use crate::bridge::macos::{get_clipboard, set_clipboard}; -use std::ffi::{CStr, CString}; - -pub struct MacClipboardManager { - -} - -impl super::ClipboardManager for MacClipboardManager { - fn get_clipboard(&self) -> Option { - unsafe { - let mut buffer : [c_char; 2000] = [0; 2000]; - let res = get_clipboard(buffer.as_mut_ptr(), buffer.len() as i32); - - if res > 0 { - let c_string = CStr::from_ptr(buffer.as_ptr()); - - let string = c_string.to_str(); - if let Ok(string) = string { - return Some((*string).to_owned()); - } - } - } - - None - } - - fn set_clipboard(&self, payload: &str) { - let res = CString::new(payload); - if let Ok(cstr) = res { - unsafe { - set_clipboard(cstr.as_ptr()); - } - } - } -} - -impl MacClipboardManager { - pub fn new() -> MacClipboardManager { - MacClipboardManager{} - } -} \ No newline at end of file diff --git a/src/clipboard/mod.rs b/src/clipboard/mod.rs deleted file mode 100644 index c99a4cc..0000000 --- a/src/clipboard/mod.rs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#[cfg(target_os = "windows")] -mod windows; - -#[cfg(target_os = "linux")] -mod linux; - -#[cfg(target_os = "macos")] -mod macos; - -pub trait ClipboardManager { - fn get_clipboard(&self) -> Option; - fn set_clipboard(&self, payload: &str); -} - -// LINUX IMPLEMENTATION -#[cfg(target_os = "linux")] -pub fn get_manager() -> impl ClipboardManager { - linux::LinuxClipboardManager::new() -} - -// WINDOWS IMPLEMENTATION -#[cfg(target_os = "windows")] -pub fn get_manager() -> impl ClipboardManager { - windows::WindowsClipboardManager::new() -} - -// MAC IMPLEMENTATION -#[cfg(target_os = "macos")] -pub fn get_manager() -> impl ClipboardManager { - macos::MacClipboardManager::new() -} \ No newline at end of file diff --git a/src/clipboard/windows.rs b/src/clipboard/windows.rs deleted file mode 100644 index caa8e0e..0000000 --- a/src/clipboard/windows.rs +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use widestring::U16CString; -use crate::bridge::windows::{set_clipboard, get_clipboard}; - -pub struct WindowsClipboardManager { - -} - -impl WindowsClipboardManager { - pub fn new() -> WindowsClipboardManager { - WindowsClipboardManager{} - } -} - -impl super::ClipboardManager for WindowsClipboardManager { - fn get_clipboard(&self) -> Option { - unsafe { - let mut buffer : [u16; 2000] = [0; 2000]; - let res = get_clipboard(buffer.as_mut_ptr(), buffer.len() as i32); - - if res > 0 { - let c_string = U16CString::from_ptr_str(buffer.as_ptr()); - - let string = c_string.to_string_lossy(); - return Some((*string).to_owned()); - } - } - - None - } - - fn set_clipboard(&self, payload: &str) { - unsafe { - let payload_c = U16CString::from_str(payload).unwrap(); - set_clipboard(payload_c.as_ptr()); - } - } -} \ No newline at end of file diff --git a/src/config/mod.rs b/src/config/mod.rs deleted file mode 100644 index 4b7f686..0000000 --- a/src/config/mod.rs +++ /dev/null @@ -1,699 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -extern crate dirs; - -use std::path::{Path, PathBuf}; -use std::{fs}; -use crate::matcher::Match; -use std::fs::{File, create_dir_all}; -use std::io::Read; -use serde::{Serialize, Deserialize}; -use crate::event::KeyModifier; -use std::collections::HashSet; -use log::{error}; -use std::fmt; -use std::error::Error; - -pub(crate) mod runtime; - -// TODO: add documentation link -const DEFAULT_CONFIG_FILE_CONTENT : &str = include_str!("../res/config.yaml"); - -const DEFAULT_CONFIG_FILE_NAME : &str = "default.yaml"; - -// Default values for primitives -fn default_name() -> String{ "default".to_owned() } -fn default_filter_title() -> String{ "".to_owned() } -fn default_filter_class() -> String{ "".to_owned() } -fn default_filter_exec() -> String{ "".to_owned() } -fn default_disabled() -> bool{ false } -fn default_log_level() -> i32 { 0 } -fn default_ipc_server_port() -> i32 { 34982 } -fn default_use_system_agent() -> bool { true } -fn default_config_caching_interval() -> i32 { 800 } -fn default_toggle_interval() -> u32 { 230 } -fn default_backspace_limit() -> i32 { 3 } -fn default_exclude_parent_matches() -> bool {false} -fn default_matches() -> Vec { Vec::new() } - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Configs { - #[serde(default = "default_name")] - pub name: String, - - #[serde(default = "default_filter_title")] - pub filter_title: String, - - #[serde(default = "default_filter_class")] - pub filter_class: String, - - #[serde(default = "default_filter_exec")] - pub filter_exec: String, - - #[serde(default = "default_disabled")] - pub disabled: bool, - - #[serde(default = "default_log_level")] - pub log_level: i32, - - #[serde(default = "default_ipc_server_port")] - pub ipc_server_port: i32, - - #[serde(default = "default_use_system_agent")] - pub use_system_agent: bool, - - #[serde(default = "default_config_caching_interval")] - pub config_caching_interval: i32, - - #[serde(default)] - pub toggle_key: KeyModifier, - - #[serde(default = "default_toggle_interval")] - pub toggle_interval: u32, - - #[serde(default = "default_backspace_limit")] - pub backspace_limit: i32, - - #[serde(default)] - pub backend: BackendType, - - #[serde(default = "default_exclude_parent_matches")] - pub exclude_parent_matches: bool, - - #[serde(default = "default_matches")] - pub matches: Vec -} - -// Macro used to validate config fields -#[macro_export] -macro_rules! validate_field { - ($result:expr, $field:expr, $def_value:expr) => { - if $field != $def_value { - let mut field_name = stringify!($field); - if field_name.starts_with("self.") { - field_name = &field_name[5..]; // Remove the 'self.' prefix - } - error!("Validation error, parameter '{}' is reserved and can be only used in the default.yaml config file", field_name); - $result = false; - } - }; -} - -impl Configs { - /* - * Validate the Config instance. - * It makes sure that app-specific config instances do not define - * attributes reserved to the default config. - */ - fn validate_specific_config(&self) -> bool { - let mut result = true; - - validate_field!(result, self.config_caching_interval, default_config_caching_interval()); - validate_field!(result, self.log_level, default_log_level()); - validate_field!(result, self.toggle_key, KeyModifier::default()); - validate_field!(result, self.toggle_interval, default_toggle_interval()); - validate_field!(result, self.backspace_limit, default_backspace_limit()); - validate_field!(result, self.ipc_server_port, default_ipc_server_port()); - validate_field!(result, self.use_system_agent, default_use_system_agent()); - - result - } -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum BackendType { - Inject, - Clipboard -} -impl Default for BackendType { - fn default() -> Self { - BackendType::Inject - } -} - -impl Configs { - fn load_config(path: &Path) -> Result { - let file_res = File::open(path); - if let Ok(mut file) = file_res { - let mut contents = String::new(); - let res = file.read_to_string(&mut contents); - - if let Err(_) = res { - return Err(ConfigLoadError::UnableToReadFile) - } - - let config_res = serde_yaml::from_str(&contents); - - match config_res { - Ok(config) => Ok(config), - Err(e) => { - Err(ConfigLoadError::InvalidYAML(path.to_owned(), e.to_string())) - } - } - }else{ - Err(ConfigLoadError::FileNotFound) - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ConfigSet { - pub default: Configs, - pub specific: Vec, -} - -impl ConfigSet { - pub fn load(dir_path: &Path) -> Result { - if !dir_path.is_dir() { - return Err(ConfigLoadError::InvalidConfigDirectory) - } - - let default_file = dir_path.join(DEFAULT_CONFIG_FILE_NAME); - let default = Configs::load_config(default_file.as_path())?; - - let mut specific = Vec::new(); - - // Used to make sure no duplicates are present - let mut name_set = HashSet::new(); - - let dir_entry = fs::read_dir(dir_path); - if dir_entry.is_err() { - return Err(ConfigLoadError::UnableToReadFile) - } - let dir_entry = dir_entry.unwrap(); - - for entry in dir_entry { - let entry = entry; - if let Ok(entry) = entry { - let path = entry.path(); - - // Skip the default one, already loaded - if path.file_name().unwrap_or("".as_ref()) == "default.yaml" { - continue; - } - - // Skip non-yaml config files - if path.extension().unwrap_or_default().to_str().unwrap_or_default() != "yaml" { - continue; - } - - let mut config = Configs::load_config(path.as_path())?; - - if !config.validate_specific_config() { - return Err(ConfigLoadError::InvalidParameter(path.to_owned())) - } - - if config.name == "default" { - return Err(ConfigLoadError::MissingName(path.to_owned())); - } - - if name_set.contains(&config.name) { - return Err(ConfigLoadError::NameDuplicate(path.to_owned())); - } - - // Compute new match set, merging the parent's matches. - // Note: if an app-specific redefines a trigger already present in the - // default config, the latter gets overwritten. - if !config.exclude_parent_matches { - let mut merged_matches = config.matches.clone(); - let mut trigger_set = HashSet::new(); - merged_matches.iter().for_each(|m| { - trigger_set.insert(m.trigger.clone()); - }); - let parent_matches : Vec = default.matches.iter().filter(|&m| { - !trigger_set.contains(&m.trigger) - }).map(|m| m.clone()).collect(); - - merged_matches.extend(parent_matches); - config.matches = merged_matches; - } - - // TODO: check if it contains at least a filter, and warn the user about the problem - - name_set.insert(config.name.clone()); - specific.push(config); - } - } - - Ok(ConfigSet { - default, - specific - }) - } - - pub fn load_default() -> Result { - let res = dirs::home_dir(); - if let Some(home_dir) = res { - let espanso_dir = home_dir.join(".espanso"); - - // Create the espanso dir if id doesn't exist - let res = create_dir_all(espanso_dir.as_path()); - - if let Ok(_) = res { - let default_file = espanso_dir.join(DEFAULT_CONFIG_FILE_NAME); - - // If config file does not exist, create one from template - if !default_file.exists() { - let result = fs::write(&default_file, DEFAULT_CONFIG_FILE_CONTENT); - if result.is_err() { - return Err(ConfigLoadError::UnableToCreateDefaultConfig) - } - } - - return ConfigSet::load(espanso_dir.as_path()) - } - } - - return Err(ConfigLoadError::UnableToCreateDefaultConfig) - } -} - -pub trait ConfigManager<'a> { - fn active_config(&'a self) -> &'a Configs; - fn default_config(&'a self) -> &'a Configs; - fn matches(&'a self) -> &'a Vec; -} - -// Error handling -#[derive(Debug, PartialEq)] -pub enum ConfigLoadError { - FileNotFound, - UnableToReadFile, - InvalidYAML(PathBuf, String), - InvalidConfigDirectory, - InvalidParameter(PathBuf), - MissingName(PathBuf), - NameDuplicate(PathBuf), - UnableToCreateDefaultConfig, -} - -impl fmt::Display for ConfigLoadError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - ConfigLoadError::FileNotFound => write!(f, "File not found"), - ConfigLoadError::UnableToReadFile => write!(f, "Unable to read config file"), - ConfigLoadError::InvalidYAML(path, e) => write!(f, "Error parsing YAML file '{}', invalid syntax: {}", path.to_str().unwrap_or_default(), e), - ConfigLoadError::InvalidConfigDirectory => write!(f, "Invalid config directory"), - ConfigLoadError::InvalidParameter(path) => write!(f, "Invalid parameter in '{}', use of reserved parameters in app-specific configs is not permitted", path.to_str().unwrap_or_default()), - ConfigLoadError::MissingName(path) => write!(f, "The 'name' field is required in app-specific configurations, but it's missing in '{}'", path.to_str().unwrap_or_default()), - ConfigLoadError::NameDuplicate(path) => write!(f, "Found duplicate 'name' in '{}', please use different names", path.to_str().unwrap_or_default()), - ConfigLoadError::UnableToCreateDefaultConfig => write!(f, "Could not generate default config file"), - } - } -} - -impl Error for ConfigLoadError { - fn description(&self) -> &str { - match self { - ConfigLoadError::FileNotFound => "File not found", - ConfigLoadError::UnableToReadFile => "Unable to read config file", - ConfigLoadError::InvalidYAML(_, _) => "Error parsing YAML file, invalid syntax", - ConfigLoadError::InvalidConfigDirectory => "Invalid config directory", - ConfigLoadError::InvalidParameter(_) => "Invalid parameter, use of reserved parameters in app-specific configs is not permitted", - ConfigLoadError::MissingName(_) => "The 'name' field is required in app-specific configurations, but it's missing", - ConfigLoadError::NameDuplicate(_) => "Found duplicate 'name' in some configurations, please use different names", - ConfigLoadError::UnableToCreateDefaultConfig => "Could not generate default config file", - } - } -} - - - -#[cfg(test)] -mod tests { - use super::*; - use std::io::Write; - use tempfile::{NamedTempFile, TempDir}; - use std::any::Any; - - const TEST_WORKING_CONFIG_FILE : &str = include_str!("../res/test/working_config.yaml"); - const TEST_CONFIG_FILE_WITH_BAD_YAML : &str = include_str!("../res/test/config_with_bad_yaml.yaml"); - - // Test Configs - - fn create_tmp_file(string: &str) -> NamedTempFile { - let file = NamedTempFile::new().unwrap(); - file.as_file().write_all(string.as_bytes()); - file - } - - fn variant_eq(a: &T, b: &T) -> bool { - std::mem::discriminant(a) == std::mem::discriminant(b) - } - - #[test] - fn test_config_file_not_found() { - let config = Configs::load_config(Path::new("invalid/path")); - assert_eq!(config.is_err(), true); - assert_eq!(config.unwrap_err(), ConfigLoadError::FileNotFound); - } - - #[test] - fn test_config_file_with_bad_yaml_syntax() { - let broken_config_file = create_tmp_file(TEST_CONFIG_FILE_WITH_BAD_YAML); - let config = Configs::load_config(broken_config_file.path()); - match config { - Ok(_) => {assert!(false)}, - Err(e) => { - match e { - ConfigLoadError::InvalidYAML(p, _) => assert_eq!(p, broken_config_file.path().to_owned()), - _ => assert!(false), - } - assert!(true); - }, - } - - } - - #[test] - fn test_validate_field_macro() { - let mut result = true; - - validate_field!(result, 3, 3); - assert_eq!(result, true); - - validate_field!(result, 10, 3); - assert_eq!(result, false); - - validate_field!(result, 3, 3); - assert_eq!(result, false); - } - - #[test] - fn test_specific_config_does_not_have_reserved_fields() { - let working_config_file = create_tmp_file(r###" - - backend: Clipboard - - "###); - let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), true); - } - - #[test] - fn test_specific_config_has_reserved_fields_config_caching_interval() { - let working_config_file = create_tmp_file(r###" - - # This should not happen in an app-specific config - config_caching_interval: 100 - - "###); - let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), false); - } - - #[test] - fn test_specific_config_has_reserved_fields_toggle_key() { - let working_config_file = create_tmp_file(r###" - - # This should not happen in an app-specific config - toggle_key: CTRL - - "###); - let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), false); - } - - #[test] - fn test_specific_config_has_reserved_fields_toggle_interval() { - let working_config_file = create_tmp_file(r###" - - # This should not happen in an app-specific config - toggle_interval: 1000 - - "###); - let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), false); - } - - #[test] - fn test_specific_config_has_reserved_fields_backspace_limit() { - let working_config_file = create_tmp_file(r###" - - # This should not happen in an app-specific config - backspace_limit: 10 - - "###); - let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.unwrap().validate_specific_config(), false); - } - - #[test] - fn test_config_loaded_correctly() { - let working_config_file = create_tmp_file(TEST_WORKING_CONFIG_FILE); - let config = Configs::load_config(working_config_file.path()); - assert_eq!(config.is_ok(), true); - } - - // Test ConfigSet - - #[test] - fn test_config_set_default_content_should_work_correctly() { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - fs::write(default_path, DEFAULT_CONFIG_FILE_CONTENT); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_ok()); - } - - #[test] - fn test_config_set_load_fail_bad_directory() { - let config_set = ConfigSet::load(Path::new("invalid/path")); - assert_eq!(config_set.is_err(), true); - assert_eq!(config_set.unwrap_err(), ConfigLoadError::InvalidConfigDirectory); - } - - #[test] - fn test_config_set_missing_default_file() { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert_eq!(config_set.is_err(), true); - assert_eq!(config_set.unwrap_err(), ConfigLoadError::FileNotFound); - } - - #[test] - fn test_config_set_invalid_yaml_syntax() { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - let default_path_copy = default_path.clone(); - fs::write(default_path, TEST_CONFIG_FILE_WITH_BAD_YAML); - - let config_set = ConfigSet::load(tmp_dir.path()); - match config_set { - Ok(_) => {assert!(false)}, - Err(e) => { - match e { - ConfigLoadError::InvalidYAML(p, _) => assert_eq!(p, default_path_copy), - _ => assert!(false), - } - assert!(true); - }, - } - } - - #[test] - fn test_config_set_specific_file_with_reserved_fields() { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - fs::write(default_path, DEFAULT_CONFIG_FILE_CONTENT); - - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" - config_caching_interval: 10000 - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_err()); - assert_eq!(config_set.unwrap_err(), ConfigLoadError::InvalidParameter(specific_path_copy)) - } - - #[test] - fn test_config_set_specific_file_missing_name() { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - fs::write(default_path, DEFAULT_CONFIG_FILE_CONTENT); - - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" - backend: Clipboard - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_err()); - assert_eq!(config_set.unwrap_err(), ConfigLoadError::MissingName(specific_path_copy)) - } - - pub fn create_temp_espanso_directory() -> TempDir { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - fs::write(default_path, DEFAULT_CONFIG_FILE_CONTENT); - - tmp_dir - } - - pub fn create_temp_file_in_dir(tmp_dir: &TempDir, name: &str, content: &str) -> PathBuf { - let specific_path = tmp_dir.path().join(name); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, content); - - specific_path_copy - } - - #[test] - fn test_config_set_specific_file_duplicate_name() { - let tmp_dir = create_temp_espanso_directory(); - - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" - name: specific1 - "###); - - let specific_path2 = create_temp_file_in_dir(&tmp_dir, "specific2.yaml", r###" - name: specific1 - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_err()); - assert!(variant_eq(&config_set.unwrap_err(), &ConfigLoadError::NameDuplicate(PathBuf::new()))) - } - - #[test] - fn test_specific_config_set_merge_with_parent_matches() { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - fs::write(default_path, r###" - matches: - - trigger: ":lol" - replace: "LOL" - - trigger: ":yess" - replace: "Bob" - "###); - - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" - name: specific1 - - matches: - - trigger: "hello" - replace: "newstring" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); - assert_eq!(config_set.default.matches.len(), 2); - assert_eq!(config_set.specific[0].matches.len(), 3); - - assert!(config_set.specific[0].matches.iter().find(|x| x.trigger == "hello").is_some()); - assert!(config_set.specific[0].matches.iter().find(|x| x.trigger == ":lol").is_some()); - assert!(config_set.specific[0].matches.iter().find(|x| x.trigger == ":yess").is_some()); - } - - #[test] - fn test_specific_config_set_merge_with_parent_matches_child_priority() { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - fs::write(default_path, r###" - matches: - - trigger: ":lol" - replace: "LOL" - - trigger: ":yess" - replace: "Bob" - "###); - - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" - name: specific1 - - matches: - - trigger: ":lol" - replace: "newstring" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); - assert_eq!(config_set.default.matches.len(), 2); - assert_eq!(config_set.specific[0].matches.len(), 2); - - assert!(config_set.specific[0].matches.iter().find(|x| x.trigger == ":lol" && x.replace == "newstring").is_some()); - assert!(config_set.specific[0].matches.iter().find(|x| x.trigger == ":yess").is_some()); - } - - #[test] - fn test_specific_config_set_exclude_merge_with_parent_matches() { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - fs::write(default_path, r###" - matches: - - trigger: ":lol" - replace: "LOL" - - trigger: ":yess" - replace: "Bob" - "###); - - let specific_path = tmp_dir.path().join("specific.yaml"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" - name: specific1 - - exclude_parent_matches: true - - matches: - - trigger: "hello" - replace: "newstring" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); - assert_eq!(config_set.default.matches.len(), 2); - assert_eq!(config_set.specific[0].matches.len(), 1); - - assert!(config_set.specific[0].matches.iter().find(|x| x.trigger == "hello" && x.replace == "newstring").is_some()); - } - - #[test] - fn test_only_yaml_files_are_loaded_from_config() { - let tmp_dir = TempDir::new().expect("unable to create temp directory"); - let default_path = tmp_dir.path().join(DEFAULT_CONFIG_FILE_NAME); - fs::write(default_path, r###" - matches: - - trigger: ":lol" - replace: "LOL" - - trigger: ":yess" - replace: "Bob" - "###); - - let specific_path = tmp_dir.path().join("specific.zzz"); - let specific_path_copy = specific_path.clone(); - fs::write(specific_path, r###" - name: specific1 - - exclude_parent_matches: true - - matches: - - trigger: "hello" - replace: "newstring" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()).unwrap(); - assert_eq!(config_set.specific.len(), 0); - } -} \ No newline at end of file diff --git a/src/config/runtime.rs b/src/config/runtime.rs deleted file mode 100644 index e817352..0000000 --- a/src/config/runtime.rs +++ /dev/null @@ -1,471 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use regex::Regex; -use crate::system::SystemManager; -use std::cell::RefCell; -use std::time::SystemTime; -use log::{debug, warn}; -use super::{Configs, ConfigSet}; -use crate::matcher::Match; - -pub struct RuntimeConfigManager<'a, S: SystemManager> { - set: ConfigSet, - - // Filter regexps - title_regexps: Vec>, - class_regexps: Vec>, - exec_regexps: Vec>, - - system_manager: S, - - // Cache - last_config_update: RefCell, - last_config: RefCell> -} - -impl <'a, S: SystemManager> RuntimeConfigManager<'a, S> { - pub fn new<'b>(set: ConfigSet, system_manager: S) -> RuntimeConfigManager<'b, S> { - // Compile all the regexps - let title_regexps = set.specific.iter().map( - |config| { - if config.filter_title.is_empty() { - None - }else{ - let res = Regex::new(&config.filter_title); - if let Ok(regex) = res { - Some(regex) - }else{ - warn!("Invalid regex in 'filter_title' field of configuration {}, ignoring it...", config.name); - None - } - } - } - ).collect(); - - let class_regexps = set.specific.iter().map( - |config| { - if config.filter_class.is_empty() { - None - }else{ - let res = Regex::new(&config.filter_class); - if let Ok(regex) = res { - Some(regex) - }else{ - warn!("Invalid regex in 'filter_class' field of configuration {}, ignoring it...", config.name); - None - } - } - } - ).collect(); - - let exec_regexps = set.specific.iter().map( - |config| { - if config.filter_exec.is_empty() { - None - }else{ - let res = Regex::new(&config.filter_exec); - if let Ok(regex) = res { - Some(regex) - }else{ - warn!("Invalid regex in 'filter_exec' field of configuration {}, ignoring it...", config.name); - None - } - } - } - ).collect(); - - let last_config_update = RefCell::new(SystemTime::now()); - let last_config = RefCell::new(None); - - RuntimeConfigManager { - set, - title_regexps, - class_regexps, - exec_regexps, - system_manager, - last_config_update, - last_config - } - } - - fn calculate_active_config(&'a self) -> &'a Configs { - // TODO: optimize performance by avoiding some of these checks if no Configs use the filters - - debug!("Requested config for window:"); - - let active_title = self.system_manager.get_current_window_title(); - - if let Some(title) = active_title { - debug!("=> Title: '{}'", title); - - for (i, regex) in self.title_regexps.iter().enumerate() { - if let Some(regex) = regex { - if regex.is_match(&title) { - debug!("Matched 'filter_title' for '{}' config, using custom settings.", - self.set.specific[i].name); - - return &self.set.specific[i] - } - } - } - } - - let active_executable = self.system_manager.get_current_window_executable(); - - if let Some(executable) = active_executable { - debug!("=> Executable: '{}'", executable); - - for (i, regex) in self.exec_regexps.iter().enumerate() { - if let Some(regex) = regex { - if regex.is_match(&executable) { - debug!("Matched 'filter_exec' for '{}' config, using custom settings.", - self.set.specific[i].name); - - return &self.set.specific[i] - } - } - } - } - - let active_class = self.system_manager.get_current_window_class(); - - if let Some(class) = active_class { - debug!("=> Class: '{}'", class); - - for (i, regex) in self.class_regexps.iter().enumerate() { - if let Some(regex) = regex { - if regex.is_match(&class) { - debug!("Matched 'filter_class' for '{}' config, using custom settings.", - self.set.specific[i].name); - - return &self.set.specific[i] - } - } - } - } - - // No matches, return the default mapping - debug!("No matches for custom configs, using default settings."); - &self.set.default - } -} - -impl <'a, S: SystemManager> super::ConfigManager<'a> for RuntimeConfigManager<'a, S> { - fn active_config(&'a self) -> &'a Configs { - let mut last_config_update = self.last_config_update.borrow_mut(); - if let Ok(elapsed) = (*last_config_update).elapsed() { - *last_config_update = SystemTime::now(); - - if elapsed.as_millis() < self.set.default.config_caching_interval as u128 { - let last_config = self.last_config.borrow(); - if let Some(cached_config) = *last_config { - debug!("Using cached config"); - return cached_config; - } - } - } - - let config = self.calculate_active_config(); - - let mut last_config = self.last_config.borrow_mut(); - *last_config = Some(config); - - config - } - - fn default_config(&'a self) -> &'a Configs { - &self.set.default - } - - fn matches(&'a self) -> &'a Vec { - &self.active_config().matches - } -} - -// TESTS - -#[cfg(test)] -mod tests { - use super::*; - use std::io::Write; - use tempfile::{NamedTempFile, TempDir}; - use crate::config::{DEFAULT_CONFIG_FILE_NAME, DEFAULT_CONFIG_FILE_CONTENT}; - use std::fs; - use std::path::PathBuf; - use crate::config::ConfigManager; - use crate::config::tests::{create_temp_espanso_directory, create_temp_file_in_dir}; - - struct DummySystemManager { - title: RefCell, - class: RefCell, - exec: RefCell, - } - impl SystemManager for DummySystemManager { - fn get_current_window_title(&self) -> Option { - Some(self.title.borrow().clone()) - } - fn get_current_window_class(&self) -> Option { - Some(self.class.borrow().clone()) - } - fn get_current_window_executable(&self) -> Option { - Some(self.exec.borrow().clone()) - } - } - impl DummySystemManager { - pub fn new_custom(title: &str, class: &str, exec: &str) -> DummySystemManager { - DummySystemManager{ - title: RefCell::new(title.to_owned()), - class: RefCell::new(class.to_owned()), - exec: RefCell::new(exec.to_owned()) - } - } - - pub fn new() -> DummySystemManager { - DummySystemManager::new_custom("title", "class", "exec") - } - - pub fn change(&self, title: &str, class: &str, exec: &str) { - *self.title.borrow_mut() = title.to_owned(); - *self.class.borrow_mut() = class.to_owned(); - *self.exec.borrow_mut() = exec.to_owned(); - } - } - - #[test] - fn test_runtime_constructor_regex_load_correctly() { - let tmp_dir = create_temp_espanso_directory(); - - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" - name: myname1 - filter_exec: "Title" - "###); - - let specific_path2 = create_temp_file_in_dir(&tmp_dir, "specific2.yaml", r###" - name: myname2 - filter_title: "Yeah" - filter_class: "Car" - "###); - - let specific_path3 = create_temp_file_in_dir(&tmp_dir, "specific3.yaml", r###" - name: myname3 - filter_title: "Nice" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_ok()); - - let dummy_system_manager = DummySystemManager::new(); - - let config_manager = RuntimeConfigManager::new(config_set.unwrap(), dummy_system_manager); - - let sp1index = config_manager.set.specific - .iter().position(|x| x.name == "myname1").unwrap(); - let sp2index = config_manager.set.specific - .iter().position(|x| x.name == "myname2").unwrap(); - let sp3index = config_manager.set.specific - .iter().position(|x| x.name == "myname3").unwrap(); - - assert_eq!(config_manager.exec_regexps.len(), 3); - assert_eq!(config_manager.title_regexps.len(), 3); - assert_eq!(config_manager.class_regexps.len(), 3); - - assert!(config_manager.class_regexps[sp1index].is_none()); - assert!(config_manager.class_regexps[sp2index].is_some()); - assert!(config_manager.class_regexps[sp3index].is_none()); - - assert!(config_manager.title_regexps[sp1index].is_none()); - assert!(config_manager.title_regexps[sp2index].is_some()); - assert!(config_manager.title_regexps[sp3index].is_some()); - - assert!(config_manager.exec_regexps[sp1index].is_some()); - assert!(config_manager.exec_regexps[sp2index].is_none()); - assert!(config_manager.exec_regexps[sp3index].is_none()); - } - - #[test] - fn test_runtime_constructor_malformed_regexes_are_ignored() { - let tmp_dir = create_temp_espanso_directory(); - - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" - name: myname1 - filter_exec: "[`-_]" - "###); - - let specific_path2 = create_temp_file_in_dir(&tmp_dir, "specific2.yaml", r###" - name: myname2 - filter_title: "[`-_]" - filter_class: "Car" - "###); - - let specific_path3 = create_temp_file_in_dir(&tmp_dir, "specific3.yaml", r###" - name: myname3 - filter_title: "Nice" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_ok()); - - let dummy_system_manager = DummySystemManager::new(); - - let config_manager = RuntimeConfigManager::new(config_set.unwrap(), dummy_system_manager); - - let sp1index = config_manager.set.specific - .iter().position(|x| x.name == "myname1").unwrap(); - let sp2index = config_manager.set.specific - .iter().position(|x| x.name == "myname2").unwrap(); - let sp3index = config_manager.set.specific - .iter().position(|x| x.name == "myname3").unwrap(); - - assert_eq!(config_manager.exec_regexps.len(), 3); - assert_eq!(config_manager.title_regexps.len(), 3); - assert_eq!(config_manager.class_regexps.len(), 3); - - assert!(config_manager.class_regexps[sp1index].is_none()); - assert!(config_manager.class_regexps[sp2index].is_some()); - assert!(config_manager.class_regexps[sp3index].is_none()); - - assert!(config_manager.title_regexps[sp1index].is_none()); - assert!(config_manager.title_regexps[sp2index].is_none()); - assert!(config_manager.title_regexps[sp3index].is_some()); - - assert!(config_manager.exec_regexps[sp1index].is_none()); - assert!(config_manager.exec_regexps[sp2index].is_none()); - assert!(config_manager.exec_regexps[sp3index].is_none()); - } - - #[test] - fn test_runtime_calculate_active_config_specific_title_match() { - let tmp_dir = create_temp_espanso_directory(); - - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" - name: chrome - filter_title: "Chrome" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_ok()); - - let dummy_system_manager = DummySystemManager::new_custom("Google Chrome", "Chrome", "C:\\Path\\chrome.exe"); - - let config_manager = RuntimeConfigManager::new(config_set.unwrap(), dummy_system_manager); - - assert_eq!(config_manager.calculate_active_config().name, "chrome"); - } - - fn test_runtime_calculate_active_config_specific_class_match() { - let tmp_dir = create_temp_espanso_directory(); - - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" - name: chrome - filter_class: "Chrome" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_ok()); - - let dummy_system_manager = DummySystemManager::new_custom("Google Chrome", "Chrome", "C:\\Path\\chrome.exe"); - - let config_manager = RuntimeConfigManager::new(config_set.unwrap(), dummy_system_manager); - - assert_eq!(config_manager.calculate_active_config().name, "chrome"); - } - - fn test_runtime_calculate_active_config_specific_exec_match() { - let tmp_dir = create_temp_espanso_directory(); - - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" - name: chrome - filter_exec: "chrome.exe" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_ok()); - - let dummy_system_manager = DummySystemManager::new_custom("Google Chrome", "Chrome", "C:\\Path\\chrome.exe"); - - let config_manager = RuntimeConfigManager::new(config_set.unwrap(), dummy_system_manager); - - assert_eq!(config_manager.calculate_active_config().name, "chrome"); - } - - fn test_runtime_calculate_active_config_specific_multi_filter_match() { - let tmp_dir = create_temp_espanso_directory(); - - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" - name: chrome - filter_class: Browser - filter_exec: "firefox.exe" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_ok()); - - let dummy_system_manager = DummySystemManager::new_custom("Google Chrome", "Browser", "C:\\Path\\chrome.exe"); - - let config_manager = RuntimeConfigManager::new(config_set.unwrap(), dummy_system_manager); - - assert_eq!(config_manager.calculate_active_config().name, "chrome"); - } - - #[test] - fn test_runtime_calculate_active_config_no_match() { - let tmp_dir = create_temp_espanso_directory(); - - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" - name: firefox - filter_title: "Firefox" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_ok()); - - let dummy_system_manager = DummySystemManager::new_custom("Google Chrome", "Chrome", "C:\\Path\\chrome.exe"); - - let config_manager = RuntimeConfigManager::new(config_set.unwrap(), dummy_system_manager); - - assert_eq!(config_manager.calculate_active_config().name, "default"); - } - - #[test] - fn test_runtime_active_config_cache() { - let tmp_dir = create_temp_espanso_directory(); - - let specific_path = create_temp_file_in_dir(&tmp_dir, "specific.yaml", r###" - name: firefox - filter_title: "Firefox" - "###); - - let config_set = ConfigSet::load(tmp_dir.path()); - assert!(config_set.is_ok()); - - let dummy_system_manager = DummySystemManager::new_custom("Google Chrome", "Chrome", "C:\\Path\\chrome.exe"); - - let config_manager = RuntimeConfigManager::new(config_set.unwrap(), dummy_system_manager); - - assert_eq!(config_manager.active_config().name, "default"); - assert_eq!(config_manager.calculate_active_config().name, "default"); - - config_manager.system_manager.change("Firefox", "Browser", "C\\Path\\firefox.exe"); - - // Active config should have changed, but not cached one - assert_eq!(config_manager.calculate_active_config().name, "firefox"); - assert_eq!(config_manager.active_config().name, "default"); - } -} \ No newline at end of file diff --git a/src/context/linux.rs b/src/context/linux.rs deleted file mode 100644 index 152ed0b..0000000 --- a/src/context/linux.rs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::sync::mpsc::Sender; -use std::os::raw::c_void; -use crate::event::*; -use crate::event::KeyModifier::*; -use crate::bridge::linux::*; -use std::process::exit; -use log::error; - -#[repr(C)] -pub struct LinuxContext { - pub send_channel: Sender -} - -impl LinuxContext { - pub fn new(send_channel: Sender) -> Box { - let context = Box::new(LinuxContext { - send_channel, - }); - - unsafe { - let context_ptr = &*context as *const LinuxContext as *const c_void; - - register_keypress_callback(keypress_callback); - - let res = initialize(context_ptr); - if res <= 0 { - error!("Could not initialize linux context, error: {}", res); - exit(10); - } - } - - context - } -} - -impl super::Context for LinuxContext { - fn eventloop(&self) { - unsafe { - eventloop(); - } - } -} - -impl Drop for LinuxContext { - fn drop(&mut self) { - unsafe { cleanup(); } - } -} - -// Native bridge code - -extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const u8, len: i32, - is_modifier: i32, key_code: i32) { - unsafe { - let _self = _self as *mut LinuxContext; - - if is_modifier == 0 { // Char event - // Convert the received buffer to a character - let buffer = std::slice::from_raw_parts(raw_buffer, len as usize); - let r = String::from_utf8_lossy(buffer).chars().nth(0); - - // Send the char through the channel - if let Some(c) = r { - let event = Event::Key(KeyEvent::Char(c)); - (*_self).send_channel.send(event).unwrap(); - } - }else{ // Modifier event - let modifier: Option = match key_code { - 133 => Some(META), - 50 => Some(SHIFT), - 64 => Some(ALT), - 37 => Some(CTRL), - 22 => Some(BACKSPACE), - _ => None, - }; - - if let Some(modifier) = modifier { - let event = Event::Key(KeyEvent::Modifier(modifier)); - (*_self).send_channel.send(event).unwrap(); - } - } - } -} \ No newline at end of file diff --git a/src/context/macos.rs b/src/context/macos.rs deleted file mode 100644 index 3e6c0ea..0000000 --- a/src/context/macos.rs +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::sync::mpsc::Sender; -use std::os::raw::c_void; -use crate::bridge::macos::*; -use crate::event::{Event, KeyEvent, KeyModifier, ActionType}; -use crate::event::KeyModifier::*; -use std::ffi::CString; -use std::fs; -use log::{info, error}; -use std::process::exit; - -const STATUS_ICON_BINARY : &'static [u8] = include_bytes!("../res/mac/icon.png"); - -pub struct MacContext { - pub send_channel: Sender -} - -impl MacContext { - pub fn new(send_channel: Sender) -> Box { - // Check accessibility - unsafe { - let res = prompt_accessibility(); - - if res == 0 { - error!("Accessibility must be enabled to make espanso work on MacOS."); - error!("Please allow espanso in the Security & Privacy panel, then restart espanso."); - error!("For more information: "); // TODO: add documentation link - exit(1); - } - } - - let context = Box::new(MacContext { - send_channel - }); - - // Initialize the status icon path - let espanso_dir = super::get_data_dir(); - let status_icon_target = espanso_dir.join("icon.png"); - - if status_icon_target.exists() { - info!("Status icon already initialized, skipping."); - }else { - fs::write(&status_icon_target, STATUS_ICON_BINARY).unwrap_or_else(|e| { - error!("Error copying the Status Icon to the espanso data directory: {}", e); - }); - } - - unsafe { - let context_ptr = &*context as *const MacContext as *const c_void; - - register_keypress_callback(keypress_callback); - register_icon_click_callback(icon_click_callback); - register_context_menu_click_callback(context_menu_click_callback); - - let status_icon_path = CString::new(status_icon_target.to_str().unwrap_or_default()).unwrap_or_default(); - initialize(context_ptr, status_icon_path.as_ptr()); - } - - context - } -} - -impl super::Context for MacContext { - fn eventloop(&self) { - unsafe { - eventloop(); - } - } -} - -// Native bridge code - -extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const u8, len: i32, - is_modifier: i32, key_code: i32) { - unsafe { - let _self = _self as *mut MacContext; - - if is_modifier == 0 { // Char event - // Convert the received buffer to a character - let buffer = std::slice::from_raw_parts(raw_buffer, len as usize); - let r = String::from_utf8_lossy(buffer).chars().nth(0); - - // Send the char through the channel - if let Some(c) = r { - let event = Event::Key(KeyEvent::Char(c)); - (*_self).send_channel.send(event).unwrap(); - } - }else{ // Modifier event - let modifier: Option = match key_code { - 0x37 => Some(META), - 0x38 => Some(SHIFT), - 0x3A => Some(ALT), - 0x3B => Some(CTRL), - 0x33 => Some(BACKSPACE), - _ => None, - }; - - if let Some(modifier) = modifier { - let event = Event::Key(KeyEvent::Modifier(modifier)); - (*_self).send_channel.send(event).unwrap(); - } - } - } -} - -extern fn icon_click_callback(_self: *mut c_void) { - unsafe { - let _self = _self as *mut MacContext; - - let event = Event::Action(ActionType::IconClick); - (*_self).send_channel.send(event).unwrap(); - } -} - -extern fn context_menu_click_callback(_self: *mut c_void, id: i32) { - unsafe { - let _self = _self as *mut MacContext; - - let event = Event::Action(ActionType::from(id)); - (*_self).send_channel.send(event).unwrap(); - } -} \ No newline at end of file diff --git a/src/context/mod.rs b/src/context/mod.rs deleted file mode 100644 index bbc1d9e..0000000 --- a/src/context/mod.rs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#[cfg(target_os = "windows")] -mod windows; - -#[cfg(target_os = "linux")] -mod linux; - -#[cfg(target_os = "macos")] -pub(crate) mod macos; - -use std::sync::mpsc::Sender; -use crate::event::Event; -use std::path::PathBuf; -use std::fs::create_dir_all; - -pub trait Context { - fn eventloop(&self); -} - -pub fn get_data_dir() -> PathBuf { - let data_dir = dirs::data_dir().expect("Can't obtain data_dir(), terminating."); - let espanso_dir = data_dir.join("espanso"); - create_dir_all(&espanso_dir).expect("Error creating espanso data directory"); - espanso_dir -} - -// MAC IMPLEMENTATION -#[cfg(target_os = "macos")] -pub fn new(send_channel: Sender) -> Box { - macos::MacContext::new(send_channel) -} - -// LINUX IMPLEMENTATION -#[cfg(target_os = "linux")] -pub fn new(send_channel: Sender) -> Box { - linux::LinuxContext::new(send_channel) -} - -// WINDOWS IMPLEMENTATION -#[cfg(target_os = "windows")] -pub fn new(send_channel: Sender) -> Box { - windows::WindowsContext::new(send_channel) -} \ No newline at end of file diff --git a/src/context/windows.rs b/src/context/windows.rs deleted file mode 100644 index d45715f..0000000 --- a/src/context/windows.rs +++ /dev/null @@ -1,158 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::sync::mpsc::Sender; -use crate::bridge::windows::*; -use crate::event::{Event, KeyEvent, KeyModifier, ActionType}; -use crate::event::KeyModifier::*; -use std::ffi::c_void; -use std::{fs}; -use widestring::U16CString; -use log::{info}; - -const BMP_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.bmp"); -const ICO_BINARY : &'static [u8] = include_bytes!("../res/win/espanso.ico"); - -pub struct WindowsContext { - send_channel: Sender, -} - -impl WindowsContext { - pub fn new(send_channel: Sender) -> Box { - // Initialize image resources - - let espanso_dir = super::get_data_dir(); - - info!("Initializing Espanso resources in {}", espanso_dir.as_path().display()); - - let espanso_bmp_image = espanso_dir.join("espansoicon.bmp"); - if espanso_bmp_image.exists() { - info!("BMP already initialized, skipping."); - }else { - fs::write(&espanso_bmp_image, BMP_BINARY) - .expect("Unable to write windows bmp file"); - - info!("Extracted bmp icon to: {}", espanso_bmp_image.to_str().unwrap_or("error")); - } - - let espanso_ico_image = espanso_dir.join("espanso.ico"); - if espanso_ico_image.exists() { - info!("ICO already initialized, skipping."); - }else { - fs::write(&espanso_ico_image, ICO_BINARY) - .expect("Unable to write windows ico file"); - - info!("Extracted 'ico' icon to: {}", espanso_ico_image.to_str().unwrap_or("error")); - } - - let bmp_icon = espanso_bmp_image.to_str().unwrap_or_default(); - let ico_icon = espanso_ico_image.to_str().unwrap_or_default(); - - let send_channel = send_channel; - - let context = Box::new(WindowsContext{ - send_channel, - }); - - unsafe { - let context_ptr = &*context as *const WindowsContext as *const c_void; - - // Register callbacks - register_keypress_callback(keypress_callback); - register_icon_click_callback(icon_click_callback); - register_context_menu_click_callback(context_menu_click_callback); - - let ico_file_c = U16CString::from_str(ico_icon).unwrap(); - let bmp_file_c = U16CString::from_str(bmp_icon).unwrap(); - - // Initialize the windows - let res = initialize(context_ptr, ico_file_c.as_ptr(), bmp_file_c.as_ptr()); - if res != 1 { - panic!("Can't initialize Windows context") - } - } - - context - } -} - -impl super::Context for WindowsContext { - fn eventloop(&self) { - unsafe { - eventloop(); - } - } -} - -// Native bridge code - -extern fn keypress_callback(_self: *mut c_void, raw_buffer: *const i32, len: i32, - is_modifier: i32, key_code: i32, is_key_down: i32) { - unsafe { - let _self = _self as *mut WindowsContext; - if is_key_down != 0 { // KEY DOWN EVENT - if is_modifier == 0 { // Char event - // Convert the received buffer to a character - let buffer = std::slice::from_raw_parts(raw_buffer, len as usize); - let r = std::char::from_u32(buffer[0] as u32); - - // Send the char through the channel - if let Some(c) = r { - let event = Event::Key(KeyEvent::Char(c)); - (*_self).send_channel.send(event).unwrap(); - } - } - }else{ // KEY UP event - if is_modifier != 0 { // Modifier event - let modifier: Option = match key_code { - 0x5B | 0x5C => Some(META), - 0x10 => Some(SHIFT), - 0x12 => Some(ALT), - 0x11 => Some(CTRL), - 0x08 => Some(BACKSPACE), - _ => None, - }; - - if let Some(modifier) = modifier { - let event = Event::Key(KeyEvent::Modifier(modifier)); - (*_self).send_channel.send(event).unwrap(); - } - } - } - } -} - -extern fn icon_click_callback(_self: *mut c_void) { - unsafe { - let _self = _self as *mut WindowsContext; - - let event = Event::Action(ActionType::IconClick); - (*_self).send_channel.send(event).unwrap(); - } -} - - -extern fn context_menu_click_callback(_self: *mut c_void, id: i32) { - unsafe { - let _self = _self as *mut WindowsContext; - - let event = Event::Action(ActionType::from(id)); - (*_self).send_channel.send(event).unwrap(); - } -} \ No newline at end of file diff --git a/src/engine.rs b/src/engine.rs deleted file mode 100644 index 84cb22b..0000000 --- a/src/engine.rs +++ /dev/null @@ -1,204 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use crate::matcher::{Match, MatchReceiver}; -use crate::keyboard::KeyboardManager; -use crate::config::ConfigManager; -use crate::config::BackendType; -use crate::clipboard::ClipboardManager; -use log::{info, warn, error}; -use crate::ui::{UIManager, MenuItem, MenuItemType}; -use crate::event::{ActionEventReceiver, ActionType}; -use crate::extension::Extension; -use std::cell::RefCell; -use std::process::exit; -use std::collections::HashMap; -use regex::{Regex, Captures}; - -pub struct Engine<'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, - U: UIManager> { - keyboard_manager: &'a S, - clipboard_manager: &'a C, - config_manager: &'a M, - ui_manager: &'a U, - - extension_map: HashMap>, - - enabled: RefCell, -} - -impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIManager> - Engine<'a, S, C, M, U> { - pub fn new(keyboard_manager: &'a S, clipboard_manager: &'a C, - config_manager: &'a M, ui_manager: &'a U, - extensions: Vec>) -> Engine<'a, S, C, M, U> { - // Register all the extensions - let mut extension_map = HashMap::new(); - for extension in extensions.into_iter() { - extension_map.insert(extension.name(), extension); - } - - let enabled = RefCell::new(true); - - Engine{keyboard_manager, - clipboard_manager, - config_manager, - ui_manager, - extension_map, - enabled - } - } - - fn build_menu(&self) -> Vec { - let mut menu = Vec::new(); - - let enabled = self.enabled.borrow(); - let toggle_text = if *enabled { - "Disable" - }else{ - "Enable" - }.to_owned(); - menu.push(MenuItem{ - item_type: MenuItemType::Button, - item_name: toggle_text, - item_id: ActionType::Toggle as i32, - }); - - menu.push(MenuItem{ - item_type: MenuItemType::Separator, - item_name: "".to_owned(), - item_id: 999, - }); - - menu.push(MenuItem{ - item_type: MenuItemType::Button, - item_name: "Exit".to_owned(), - item_id: ActionType::Exit as i32, - }); - - menu - } -} - -lazy_static! { - static ref VAR_REGEX: Regex = Regex::new("\\{\\{\\s*(?P\\w+)\\s*\\}\\}").unwrap(); -} - -impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIManager> - MatchReceiver for Engine<'a, S, C, M, U>{ - - fn on_match(&self, m: &Match) { - let config = self.config_manager.active_config(); - - if config.disabled { - return; - } - - self.keyboard_manager.delete_string(m.trigger.len() as i32); - - let target_string = if m._has_vars { - let mut output_map = HashMap::new(); - - for variable in m.vars.iter() { - let extension = self.extension_map.get(&variable.var_type); - if let Some(extension) = extension { - let ext_out = extension.calculate(&variable.params); - if let Some(output) = ext_out { - output_map.insert(variable.name.clone(), output); - }else{ - output_map.insert(variable.name.clone(), "".to_owned()); - warn!("Could not generate output for variable: {}", variable.name); - } - }else{ - error!("No extension found for variable type: {}", variable.var_type); - } - } - - // Replace the variables - let result = VAR_REGEX.replace_all(&m.replace, |caps: &Captures| { - let var_name = caps.name("name").unwrap().as_str(); - let output = output_map.get(var_name); - output.unwrap() - }); - - result.to_string() - }else{ // No variables, simple text substitution - m.replace.clone() - }; - - match config.backend { - BackendType::Inject => { - // Send the expected string. On linux, newlines are managed automatically - // while on windows and macos, we need to emulate a Enter key press. - - if cfg!(target_os = "linux") { - self.keyboard_manager.send_string(&target_string); - }else{ - // To handle newlines, substitute each "\n" char with an Enter key press. - let splits = target_string.lines(); - - for (i, split) in splits.enumerate() { - if i > 0 { - self.keyboard_manager.send_enter(); - } - - self.keyboard_manager.send_string(split); - } - } - }, - BackendType::Clipboard => { - self.clipboard_manager.set_clipboard(&target_string); - self.keyboard_manager.trigger_paste(); - }, - } - } - - fn on_enable_update(&self, status: bool) { - let message = if status { - "espanso enabled" - }else{ - "espanso disabled" - }; - - info!("Toggled: {}", message); - - let mut enabled_ref = self.enabled.borrow_mut(); - *enabled_ref = status; - - self.ui_manager.notify(message); - } -} - -impl <'a, S: KeyboardManager, C: ClipboardManager, - M: ConfigManager<'a>, U: UIManager> ActionEventReceiver for Engine<'a, S, C, M, U>{ - - fn on_action_event(&self, e: ActionType) { - match e { - ActionType::IconClick => { - self.ui_manager.show_menu(self.build_menu()); - }, - ActionType::Exit => { - info!("Terminating espanso."); - self.ui_manager.cleanup(); - exit(0); - }, - _ => {} - } - } -} \ No newline at end of file diff --git a/src/event/manager.rs b/src/event/manager.rs deleted file mode 100644 index a119122..0000000 --- a/src/event/manager.rs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use crate::event::{KeyEventReceiver, ActionEventReceiver, Event}; -use std::sync::mpsc::Receiver; - -pub trait EventManager { - fn eventloop(&self); -} - -pub struct DefaultEventManager<'a> { - receive_channel: Receiver, - key_receivers: Vec<&'a dyn KeyEventReceiver>, - action_receivers: Vec<&'a dyn ActionEventReceiver>, -} - -impl<'a> DefaultEventManager<'a> { - pub fn new(receive_channel: Receiver, key_receivers: Vec<&'a dyn KeyEventReceiver>, - action_receivers: Vec<&'a dyn ActionEventReceiver>) -> DefaultEventManager<'a> { - DefaultEventManager { - receive_channel, - key_receivers, - action_receivers, - } - } -} - -impl <'a> EventManager for DefaultEventManager<'a> { - fn eventloop(&self) { - loop { - match self.receive_channel.recv() { - Ok(event) => { - match event { - Event::Key(key_event) => { - self.key_receivers.iter().for_each(move |&receiver| receiver.on_key_event(key_event.clone())); - }, - Event::Action(action_event) => { - self.action_receivers.iter().for_each(|&receiver| receiver.on_action_event(action_event.clone())); - } - } - }, - Err(_) => panic!("Broken event channel"), - } - } - } -} \ No newline at end of file diff --git a/src/event/mod.rs b/src/event/mod.rs deleted file mode 100644 index abcfdcc..0000000 --- a/src/event/mod.rs +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -pub(crate) mod manager; - -use serde::{Serialize, Deserialize}; - -#[derive(Debug, Clone)] -pub enum Event { - Action(ActionType), - Key(KeyEvent) -} - -#[derive(Debug, Clone)] -pub enum ActionType { - Noop = 0, - Toggle = 1, - Exit = 2, - IconClick = 3, - Enable = 4, - Disable = 5, -} - -impl From for ActionType { - fn from(id: i32) -> Self { - match id { - 1 => ActionType::Toggle, - 2 => ActionType::Exit, - 3 => ActionType::IconClick, - 4 => ActionType::Enable, - 5 => ActionType::Disable, - _ => ActionType::Noop, - } - } -} - -#[derive(Debug, Clone)] -pub enum KeyEvent { - Char(char), - Modifier(KeyModifier) -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum KeyModifier { - CTRL, - SHIFT, - ALT, - META, - BACKSPACE, -} - -impl Default for KeyModifier { - fn default() -> Self { - KeyModifier::ALT - } -} - -// Receivers - -pub trait KeyEventReceiver { - fn on_key_event(&self, e: KeyEvent); -} - -pub trait ActionEventReceiver { - fn on_action_event(&self, e: ActionType); -} \ No newline at end of file diff --git a/src/extension/date.rs b/src/extension/date.rs deleted file mode 100644 index ea64bd8..0000000 --- a/src/extension/date.rs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use serde_yaml::{Mapping, Value}; -use chrono::{DateTime, Utc}; - -pub struct DateExtension {} - -impl DateExtension { - pub fn new() -> DateExtension { - DateExtension{} - } -} - -impl super::Extension for DateExtension { - fn name(&self) -> String { - String::from("date") - } - - fn calculate(&self, params: &Mapping) -> Option { - let now: DateTime = Utc::now(); - - let format = params.get(&Value::from("format")); - - let date = if let Some(format) = format { - now.format(format.as_str().unwrap()).to_string() - }else{ - now.to_rfc2822() - }; - - Some(date) - } -} \ No newline at end of file diff --git a/src/extension/mod.rs b/src/extension/mod.rs deleted file mode 100644 index 26da4cd..0000000 --- a/src/extension/mod.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use serde_yaml::Mapping; - -mod date; -mod shell; -mod script; - -pub trait Extension { - fn name(&self) -> String; - fn calculate(&self, params: &Mapping) -> Option; -} - -pub fn get_extensions() -> Vec> { - vec![ - Box::new(date::DateExtension::new()), - Box::new(shell::ShellExtension::new()), - Box::new(script::ScriptExtension::new()), - ] -} \ No newline at end of file diff --git a/src/extension/script.rs b/src/extension/script.rs deleted file mode 100644 index a5519aa..0000000 --- a/src/extension/script.rs +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use serde_yaml::{Mapping, Value}; -use std::process::Command; -use log::{warn, error}; - -pub struct ScriptExtension {} - -impl ScriptExtension { - pub fn new() -> ScriptExtension { - ScriptExtension{} - } -} - -impl super::Extension for ScriptExtension { - fn name(&self) -> String { - String::from("script") - } - - fn calculate(&self, params: &Mapping) -> Option { - let args = params.get(&Value::from("args")); - if args.is_none() { - warn!("No 'args' parameter specified for script variable"); - return None - } - let args = args.unwrap().as_sequence(); - if let Some(args) = args { - let str_args = args.iter().map(|arg| { - arg.as_str().unwrap_or_default().to_string() - }).collect::>(); - - let output = if str_args.len() > 1 { - Command::new(&str_args[0]) - .args(&str_args[1..]) - .output() - }else{ - Command::new(&str_args[0]) - .output() - }; - - match output { - Ok(output) => { - let output_str = String::from_utf8_lossy(output.stdout.as_slice()); - - return Some(output_str.into_owned()) - }, - Err(e) => { - error!("Could not execute script '{:?}', error: {}", args, e); - return None - }, - } - } - - error!("Could not execute script with args '{:?}'", args); - None - } -} \ No newline at end of file diff --git a/src/extension/shell.rs b/src/extension/shell.rs deleted file mode 100644 index 4ca4999..0000000 --- a/src/extension/shell.rs +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use serde_yaml::{Mapping, Value}; -use std::process::Command; -use log::{warn, error}; - -pub struct ShellExtension {} - -impl ShellExtension { - pub fn new() -> ShellExtension { - ShellExtension{} - } -} - -impl super::Extension for ShellExtension { - fn name(&self) -> String { - String::from("shell") - } - - fn calculate(&self, params: &Mapping) -> Option { - let cmd = params.get(&Value::from("cmd")); - if cmd.is_none() { - warn!("No 'cmd' parameter specified for shell variable"); - return None - } - let cmd = cmd.unwrap().as_str().unwrap(); - - let output = if cfg!(target_os = "windows") { - Command::new("cmd") - .args(&["/C", cmd]) - .output() - } else { - Command::new("sh") - .arg("-c") - .arg(cmd) - .output() - }; - - match output { - Ok(output) => { - let output_str = String::from_utf8_lossy(output.stdout.as_slice()); - - Some(output_str.into_owned()) - }, - Err(e) => { - error!("Could not execute cmd '{}', error: {}", cmd, e); - None - }, - } - } -} \ No newline at end of file diff --git a/src/keyboard/linux.rs b/src/keyboard/linux.rs deleted file mode 100644 index 4b9f15b..0000000 --- a/src/keyboard/linux.rs +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::ffi::CString; -use crate::bridge::linux::*; - -pub struct LinuxKeyboardManager { -} - -impl super::KeyboardManager for LinuxKeyboardManager { - fn send_string(&self, s: &str) { - let res = CString::new(s); - match res { - Ok(cstr) => unsafe { send_string(cstr.as_ptr()); } - Err(e) => panic!(e.to_string()) - } - } - - fn send_enter(&self) { - // On linux this is not needed, so NOOP - } - - fn trigger_paste(&self) { - unsafe { - let is_terminal = is_current_window_terminal(); - - // Terminals use a different keyboard combination to paste from clipboard, - // so we need to check the correct situation. - if is_terminal == 0 { - trigger_paste(); - }else{ - trigger_terminal_paste(); - } - } - } - - fn delete_string(&self, count: i32) { - unsafe {delete_string(count)} - } -} \ No newline at end of file diff --git a/src/keyboard/macos.rs b/src/keyboard/macos.rs deleted file mode 100644 index 7381dc1..0000000 --- a/src/keyboard/macos.rs +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::ffi::CString; -use crate::bridge::macos::*; - -pub struct MacKeyboardManager { -} - -impl super::KeyboardManager for MacKeyboardManager { - fn send_string(&self, s: &str) { - let res = CString::new(s); - match res { - Ok(cstr) => unsafe { send_string(cstr.as_ptr()); } - Err(e) => panic!(e.to_string()) - } - } - - fn send_enter(&self) { - unsafe { - // Send the kVK_Return key press - send_vkey(0x24); - } - } - - fn trigger_paste(&self) { - unsafe { - trigger_paste(); - } - } - - fn delete_string(&self, count: i32) { - unsafe {delete_string(count)} - } -} \ No newline at end of file diff --git a/src/keyboard/mod.rs b/src/keyboard/mod.rs deleted file mode 100644 index c48134c..0000000 --- a/src/keyboard/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#[cfg(target_os = "windows")] -mod windows; - -#[cfg(target_os = "linux")] -mod linux; - -#[cfg(target_os = "macos")] -mod macos; - -pub trait KeyboardManager { - fn send_string(&self, s: &str); - fn send_enter(&self); - fn trigger_paste(&self); - fn delete_string(&self, count: i32); -} - -// WINDOWS IMPLEMENTATION -#[cfg(target_os = "windows")] -pub fn get_manager() -> impl KeyboardManager { - windows::WindowsKeyboardManager{} -} - -// LINUX IMPLEMENTATION -#[cfg(target_os = "linux")] -pub fn get_manager() -> impl KeyboardManager { - linux::LinuxKeyboardManager{} -} - -// MAC IMPLEMENTATION -#[cfg(target_os = "macos")] -pub fn get_manager() -> impl KeyboardManager { - macos::MacKeyboardManager{} -} \ No newline at end of file diff --git a/src/keyboard/windows.rs b/src/keyboard/windows.rs deleted file mode 100644 index df3564d..0000000 --- a/src/keyboard/windows.rs +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use widestring::{U16CString}; -use crate::bridge::windows::*; - -pub struct WindowsKeyboardManager { -} - -impl super::KeyboardManager for WindowsKeyboardManager { - fn send_string(&self, s: &str) { - let res = U16CString::from_str(s); - match res { - Ok(s) => { - unsafe { - send_string(s.as_ptr()); - } - } - Err(e) => println!("Error while sending string: {}", e.to_string()) - } - - } - - fn send_enter(&self) { - unsafe { - // Send the VK_RETURN key press - send_vkey(0x0D); - } - } - - fn trigger_paste(&self) { - unsafe { - trigger_paste(); - } - } - - fn delete_string(&self, count: i32) { - unsafe { - delete_string(count) - } - } -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 45973d0..0000000 --- a/src/main.rs +++ /dev/null @@ -1,585 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#[macro_use] -extern crate lazy_static; - -use std::thread; -use std::fs::{File, OpenOptions}; -use std::path::Path; -use std::process::exit; -use std::sync::mpsc; -use std::sync::mpsc::Receiver; -use std::time::Duration; - -use clap::{App, Arg, SubCommand, ArgMatches}; -use fs2::FileExt; -use log::{info, warn, LevelFilter}; -use simplelog::{CombinedLogger, SharedLogger, TerminalMode, TermLogger, WriteLogger}; - -use crate::config::ConfigSet; -use crate::config::runtime::RuntimeConfigManager; -use crate::engine::Engine; -use crate::event::*; -use crate::event::manager::{DefaultEventManager, EventManager}; -use crate::matcher::scrolling::ScrollingMatcher; -use crate::system::SystemManager; -use crate::ui::UIManager; -use crate::protocol::*; -use std::io::{BufReader, BufRead}; - -mod ui; -mod event; -mod check; -mod bridge; -mod engine; -mod config; -mod system; -mod sysdaemon; -mod context; -mod matcher; -mod keyboard; -mod protocol; -mod clipboard; -mod extension; - -const VERSION: &'static str = env!("CARGO_PKG_VERSION"); -const LOG_FILE: &str = "espanso.log"; - -fn main() { - let matches = App::new("espanso") - .version(VERSION) - .author("Federico Terzi") - .about("Cross-platform Text Expander written in Rust") - .arg(Arg::with_name("config") - .short("c") - .long("config") - .value_name("FILE") - .help("Sets a custom config directory. If not specified, reads the default $HOME/.espanso/default.yaml file, creating it if not present.") - .takes_value(true)) - .arg(Arg::with_name("v") - .short("v") - .multiple(true) - .help("Sets the level of verbosity")) - .subcommand(SubCommand::with_name("cmd") - .about("Send a command to the espanso daemon.") - .subcommand(SubCommand::with_name("exit") - .about("Terminate the daemon.")) - .subcommand(SubCommand::with_name("enable") - .about("Enable the espanso replacement engine.")) - .subcommand(SubCommand::with_name("disable") - .about("Disable the espanso replacement engine.")) - .subcommand(SubCommand::with_name("toggle") - .about("Toggle the status of the espanso replacement engine.")) - ) - .subcommand(SubCommand::with_name("dump") - .about("Prints all current configuration options.")) - .subcommand(SubCommand::with_name("detect") - .about("Tool to detect current window properties, to simplify filters creation.")) - .subcommand(SubCommand::with_name("daemon") - .about("Start the daemon without spawning a new process.")) - .subcommand(SubCommand::with_name("register") - .about("MacOS only. Register espanso in the system daemon manager.")) - .subcommand(SubCommand::with_name("unregister") - .about("MacOS only. Unregister espanso from the system daemon manager.")) - .subcommand(SubCommand::with_name("log") - .about("Print the latest daemon logs.")) - .subcommand(SubCommand::with_name("start") - .about("Start the daemon spawning a new process in the background.")) - .subcommand(SubCommand::with_name("stop") - .about("Stop the espanso daemon.")) - .subcommand(SubCommand::with_name("restart") - .about("Restart the espanso daemon.")) - .subcommand(SubCommand::with_name("status") - .about("Check if the espanso daemon is running or not.")) - .get_matches(); - - let log_level = matches.occurrences_of("v") as i32; - - // Load the configuration - let mut config_set = match matches.value_of("config") { - None => { - if log_level > 1 { - println!("loading configuration from default location..."); - } - ConfigSet::load_default() - }, - Some(path) => { - if log_level > 1 { - println!("loading configuration from custom location: {}", path); - } - ConfigSet::load(Path::new(path)) - }, - }.unwrap_or_else(|e| { - println!("{}", e); - exit(1); - }); - - config_set.default.log_level = log_level; - - // Match the correct subcommand - - if let Some(matches) = matches.subcommand_matches("cmd") { - cmd_main(config_set, matches); - return; - } - - if let Some(_) = matches.subcommand_matches("dump") { - println!("{:#?}", config_set); - return; - } - - if let Some(_) = matches.subcommand_matches("detect") { - detect_main(); - return; - } - - if let Some(_) = matches.subcommand_matches("daemon") { - daemon_main(config_set); - return; - } - - if let Some(_) = matches.subcommand_matches("register") { - register_main(config_set); - return; - } - - if let Some(_) = matches.subcommand_matches("unregister") { - unregister_main(config_set); - return; - } - - if let Some(_) = matches.subcommand_matches("log") { - log_main(); - return; - } - - if let Some(_) = matches.subcommand_matches("start") { - start_main(config_set); - return; - } - - if let Some(_) = matches.subcommand_matches("status") { - status_main(); - return; - } - - if let Some(_) = matches.subcommand_matches("stop") { - stop_main(config_set); - return; - } - - if let Some(_) = matches.subcommand_matches("restart") { - restart_main(config_set); - return; - } - - // Defaults to start subcommand - start_main(config_set); -} - -/// Daemon subcommand, start the event loop and spawn a background thread worker -fn daemon_main(config_set: ConfigSet) { - // Try to acquire lock file - let lock_file = acquire_lock(); - if lock_file.is_none() { - println!("espanso is already running."); - exit(3); - } - - precheck_guard(); - - // Initialize log - let log_level = match config_set.default.log_level { - 0 => LevelFilter::Warn, - 1 => LevelFilter::Info, - 2 | _ => LevelFilter::Debug, - }; - - let mut log_outputs: Vec> = Vec::new(); - - // Initialize terminal output - let terminal_out = TermLogger::new(log_level, - simplelog::Config::default(), TerminalMode::Mixed); - if let Some(terminal_out) = terminal_out { - log_outputs.push(terminal_out); - } - - // Initialize log file output - let espanso_dir = context::get_data_dir(); - let log_file_path = espanso_dir.join(LOG_FILE); - let log_file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .truncate(true) - .open(log_file_path) - .expect("Cannot create log file."); - let file_out = WriteLogger::new(LevelFilter::Info, simplelog::Config::default(), log_file); - log_outputs.push(file_out); - - CombinedLogger::init( - log_outputs - ).expect("Error opening log destination"); - - // Activate logging for panics - log_panics::init(); - - info!("espanso version {}", VERSION); - info!("starting daemon..."); - - let (send_channel, receive_channel) = mpsc::channel(); - - let context = context::new(send_channel.clone()); - - let config_set_copy = config_set.clone(); - thread::Builder::new().name("daemon_background".to_string()).spawn(move || { - daemon_background(receive_channel, config_set_copy); - }).expect("Unable to spawn daemon background thread"); - - let ipc_server = protocol::get_ipc_server(config_set, send_channel.clone()); - ipc_server.start(); - - context.eventloop(); -} - -/// Background thread worker for the daemon -fn daemon_background(receive_channel: Receiver, config_set: ConfigSet) { - let system_manager = system::get_manager(); - let config_manager = RuntimeConfigManager::new(config_set, system_manager); - - let ui_manager = ui::get_uimanager(); - ui_manager.notify("espanso is running!"); - - let clipboard_manager = clipboard::get_manager(); - - let keyboard_manager = keyboard::get_manager(); - - let extensions = extension::get_extensions(); - - let engine = Engine::new(&keyboard_manager, - &clipboard_manager, - &config_manager, - &ui_manager, - extensions, - ); - - let matcher = ScrollingMatcher::new(&config_manager, &engine); - - let event_manager = DefaultEventManager::new( - receive_channel, - vec!(&matcher), - vec!(&engine, &matcher), - ); - - info!("espanso is running!"); - - event_manager.eventloop(); -} - -/// start subcommand, spawn a background espanso process. -fn start_main(config_set: ConfigSet) { - // Try to acquire lock file - let lock_file = acquire_lock(); - if lock_file.is_none() { - println!("espanso is already running."); - exit(3); - } - release_lock(lock_file.unwrap()); - - precheck_guard(); - - start_daemon(config_set); -} - -#[cfg(target_os = "windows")] -fn start_daemon(_: ConfigSet) { - unsafe { - let res = bridge::windows::start_daemon_process(); - if res < 0 { - println!("Error starting daemon process"); - } - } -} - -#[cfg(target_os = "macos")] -fn start_daemon(config_set: ConfigSet) { - if config_set.default.use_system_agent { - use std::process::Command; - - let res = Command::new("launchctl") - .args(&["start", "com.federicoterzi.espanso"]) - .status(); - - if let Ok(status) = res { - if status.success() { - println!("Daemon started correctly!") - }else{ - println!("Error starting launchd daemon with status: {}", status); - } - }else{ - println!("Error starting launchd daemon: {}", res.unwrap_err()); - } - }else{ - fork_daemon(config_set); - } -} - -#[cfg(target_os = "linux")] -fn start_daemon(config_set: ConfigSet) { - if config_set.default.use_system_agent { - // TODO: systemd - }else{ - fork_daemon(config_set); - } -} - -#[cfg(not(target_os = "windows"))] -fn fork_daemon(config_set: ConfigSet) { - unsafe { - let pid = libc::fork(); - if pid < 0 { - println!("Unable to fork."); - exit(4); - } - if pid > 0 { // Parent process exit - println!("daemon started!"); - exit(0); - } - - // Spawned process - - // Create a new SID for the child process - let sid = libc::setsid(); - if sid < 0 { - exit(5); - } - - // Detach stdout and stderr - let null_path = std::ffi::CString::new("/dev/null").expect("CString unwrap failed"); - let fd = libc::open(null_path.as_ptr(), libc::O_RDWR, 0); - if fd != -1 { - libc::dup2(fd, libc::STDIN_FILENO); - libc::dup2(fd, libc::STDOUT_FILENO); - libc::dup2(fd, libc::STDERR_FILENO); - } - } - - daemon_main(config_set); -} - -/// status subcommand, print the current espanso status -fn status_main() { - let lock_file = acquire_lock(); - if let Some(lock_file) = lock_file { - println!("espanso is not running"); - - release_lock(lock_file); - }else{ - println!("espanso is running"); - } -} - - -/// Stop subcommand, used to stop the daemon. -fn stop_main(config_set: ConfigSet) { - // Try to acquire lock file - let lock_file = acquire_lock(); - if lock_file.is_some() { - println!("espanso daemon is not running."); - release_lock(lock_file.unwrap()); - exit(3); - } - - let res = send_command(config_set, IPCCommand{ - id: "exit".to_owned(), - payload: "".to_owned(), - }); - - if let Err(e) = res { - println!("{}", e); - exit(1); - }else{ - exit(0); - } -} - -/// Kill the daemon if running and start it again -fn restart_main(config_set: ConfigSet) { - // Kill the daemon if running - let lock_file = acquire_lock(); - if lock_file.is_none() { - // Terminate the current espanso daemon - send_command(config_set.clone(), IPCCommand{ - id: "exit".to_owned(), - payload: "".to_owned(), - }).unwrap_or_else(|e| warn!("Unable to send IPC command to daemon: {}", e)); - }else{ - release_lock(lock_file.unwrap()); - } - - std::thread::sleep(Duration::from_millis(300)); - - // Restart the daemon - start_main(config_set); -} - -/// Cli tool used to analyze active windows to extract useful information -/// to create configuration filters. -fn detect_main() { - let system_manager = system::get_manager(); - - println!("Listening for changes, now focus the window you want to analyze."); - println!("You can terminate with CTRL+C\n"); - - let mut last_title : String = "".to_owned(); - let mut last_class : String = "".to_owned(); - let mut last_exec : String = "".to_owned(); - - loop { - let curr_title = system_manager.get_current_window_title().unwrap_or_default(); - let curr_class = system_manager.get_current_window_class().unwrap_or_default(); - let curr_exec = system_manager.get_current_window_executable().unwrap_or_default(); - - // Check if a change occurred - if curr_title != last_title || curr_class != last_class || curr_exec != last_exec { - println!("Detected change, current window has properties:"); - println!("==> Title: '{}'", curr_title); - println!("==> Class: '{}'", curr_class); - println!("==> Executable: '{}'", curr_exec); - println!(); - } - - last_title = curr_title; - last_class = curr_class; - last_exec = curr_exec; - - thread::sleep(Duration::from_millis(500)); - } -} - -/// Send the given command to the espanso daemon -fn cmd_main(config_set: ConfigSet, matches: &ArgMatches) { - let command = if let Some(_) = matches.subcommand_matches("exit") { - Some(IPCCommand { - id: String::from("exit"), - payload: String::from(""), - }) - }else if let Some(_) = matches.subcommand_matches("toggle") { - Some(IPCCommand { - id: String::from("toggle"), - payload: String::from(""), - }) - }else if let Some(_) = matches.subcommand_matches("enable") { - Some(IPCCommand { - id: String::from("enable"), - payload: String::from(""), - }) - }else if let Some(_) = matches.subcommand_matches("disable") { - Some(IPCCommand { - id: String::from("disable"), - payload: String::from(""), - }) - }else{ - None - }; - - if let Some(command) = command { - let res = send_command(config_set, command); - - if res.is_ok() { - exit(0); - }else{ - println!("{}", res.unwrap_err()); - } - } - - exit(1); -} - -fn send_command(config_set: ConfigSet, command: IPCCommand) -> Result<(), String> { - let ipc_client = protocol::get_ipc_client(config_set); - ipc_client.send_command(command) -} - -fn log_main() { - let espanso_dir = context::get_data_dir(); - let log_file_path = espanso_dir.join(LOG_FILE); - - if !log_file_path.exists() { - println!("No log file found."); - exit(2); - } - - let log_file = File::open(log_file_path); - if let Ok(log_file) = log_file { - let reader = BufReader::new(log_file); - for line in reader.lines() { - if let Ok(line) = line { - println!("{}", line); - } - } - - exit(0); - }else{ - println!("Error reading log file"); - exit(1); - } -} - -fn register_main(config_set: ConfigSet) { - sysdaemon::register(config_set); -} - -fn unregister_main(config_set: ConfigSet) { - sysdaemon::unregister(config_set); -} - -fn acquire_lock() -> Option { - let espanso_dir = context::get_data_dir(); - let lock_file_path = espanso_dir.join("espanso.lock"); - let file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(lock_file_path) - .expect("Cannot create reference to lock file."); - - let res = file.try_lock_exclusive(); - - if let Ok(_) = res { - return Some(file) - } - - None -} - -fn release_lock(lock_file: File) { - lock_file.unlock().unwrap() -} - -/// Used to make sure all the required dependencies are present before starting espanso. -fn precheck_guard() { - let satisfied = check::check_dependencies(); - if !satisfied { - println!(); - println!("Pre-check was not successful, espanso could not be started."); - exit(5); - } -} \ No newline at end of file diff --git a/src/matcher/mod.rs b/src/matcher/mod.rs deleted file mode 100644 index ece4eac..0000000 --- a/src/matcher/mod.rs +++ /dev/null @@ -1,152 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use serde::{Serialize, Deserialize, Deserializer}; -use crate::event::{KeyEvent, KeyModifier}; -use crate::event::KeyEventReceiver; -use serde_yaml::Mapping; -use regex::Regex; - -pub(crate) mod scrolling; - -#[derive(Debug, Serialize, Clone)] -pub struct Match { - pub trigger: String, - pub replace: String, - pub vars: Vec, - - #[serde(skip_serializing)] - pub _has_vars: bool, -} - -impl <'de> serde::Deserialize<'de> for Match { - fn deserialize(deserializer: D) -> Result where - D: Deserializer<'de> { - - let auto_match = AutoMatch::deserialize(deserializer)?; - Ok(Match::from(&auto_match)) - } -} - -impl<'a> From<&'a AutoMatch> for Match{ - fn from(other: &'a AutoMatch) -> Self { - lazy_static! { - static ref VAR_REGEX: Regex = Regex::new("\\{\\{\\s*(\\w+)\\s*\\}\\}").unwrap(); - } - - // Check if the match contains variables - let has_vars = VAR_REGEX.is_match(&other.replace); - - Self { - trigger: other.trigger.clone(), - replace: other.replace.clone(), - vars: other.vars.clone(), - _has_vars: has_vars, - } - } -} - -/// Used to deserialize the Match struct before applying some custom elaboration. -#[derive(Debug, Serialize, Deserialize, Clone)] -struct AutoMatch { - pub trigger: String, - pub replace: String, - - #[serde(default = "default_vars")] - pub vars: Vec, -} - -fn default_vars() -> Vec {Vec::new()} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct MatchVariable { - pub name: String, - - #[serde(rename = "type")] - pub var_type: String, - - pub params: Mapping, -} - -pub trait MatchReceiver { - fn on_match(&self, m: &Match); - fn on_enable_update(&self, status: bool); -} - -pub trait Matcher : KeyEventReceiver { - fn handle_char(&self, c: char); - fn handle_modifier(&self, m: KeyModifier); -} - -impl KeyEventReceiver for M { - fn on_key_event(&self, e: KeyEvent) { - match e { - KeyEvent::Char(c) => { - self.handle_char(c); - }, - KeyEvent::Modifier(m) => { - self.handle_modifier(m); - }, - } - } -} - - -// TESTS - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_match_has_vars_should_be_false() { - let match_str = r###" - trigger: ":test" - replace: "There are no variables" - "###; - - let _match : Match = serde_yaml::from_str(match_str).unwrap(); - - assert_eq!(_match._has_vars, false); - } - - #[test] - fn test_match_has_vars_should_be_true() { - let match_str = r###" - trigger: ":test" - replace: "There are {{one}} and {{two}} variables" - "###; - - let _match : Match = serde_yaml::from_str(match_str).unwrap(); - - assert_eq!(_match._has_vars, true); - } - - #[test] - fn test_match_has_vars_with_spaces_should_be_true() { - let match_str = r###" - trigger: ":test" - replace: "There is {{ one }} variable" - "###; - - let _match : Match = serde_yaml::from_str(match_str).unwrap(); - - assert_eq!(_match._has_vars, true); - } -} \ No newline at end of file diff --git a/src/matcher/scrolling.rs b/src/matcher/scrolling.rs deleted file mode 100644 index a14df4a..0000000 --- a/src/matcher/scrolling.rs +++ /dev/null @@ -1,166 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use crate::matcher::{Match, MatchReceiver}; -use std::cell::RefCell; -use crate::event::{KeyModifier, ActionEventReceiver, ActionType}; -use crate::config::ConfigManager; -use crate::event::KeyModifier::BACKSPACE; -use std::time::SystemTime; -use std::collections::VecDeque; - -pub struct ScrollingMatcher<'a, R: MatchReceiver, M: ConfigManager<'a>> { - config_manager: &'a M, - receiver: &'a R, - current_set_queue: RefCell>>>, - toggle_press_time: RefCell, - is_enabled: RefCell, -} - -struct MatchEntry<'a> { - start: usize, - _match: &'a Match -} - -impl <'a, R: MatchReceiver, M: ConfigManager<'a>> ScrollingMatcher<'a, R, M> { - pub fn new(config_manager: &'a M, receiver: &'a R) -> ScrollingMatcher<'a, R, M> { - let current_set_queue = RefCell::new(VecDeque::new()); - let toggle_press_time = RefCell::new(SystemTime::now()); - - ScrollingMatcher{ - config_manager, - receiver, - current_set_queue, - toggle_press_time, - is_enabled: RefCell::new(true) - } - } - - fn toggle(&self) { - let mut is_enabled = self.is_enabled.borrow_mut(); - *is_enabled = !(*is_enabled); - - self.receiver.on_enable_update(*is_enabled); - } - - fn set_enabled(&self, enabled: bool) { - let mut is_enabled = self.is_enabled.borrow_mut(); - *is_enabled = enabled; - - self.receiver.on_enable_update(*is_enabled); - } -} - -impl <'a, R: MatchReceiver, M: ConfigManager<'a>> super::Matcher for ScrollingMatcher<'a, R, M> { - fn handle_char(&self, c: char) { - // if not enabled, avoid any processing - if !*(self.is_enabled.borrow()) { - return; - } - - let mut current_set_queue = self.current_set_queue.borrow_mut(); - - let new_matches: Vec = self.config_manager.matches().iter() - .filter(|&x| x.trigger.chars().nth(0).unwrap() == c) - .map(|x | MatchEntry{start: 1, _match: &x}) - .collect(); - // TODO: use an associative structure to improve the efficiency of this first "new_matches" lookup. - - let combined_matches: Vec = match current_set_queue.back() { - Some(last_matches) => { - let mut updated: Vec = last_matches.iter() - .filter(|&x| { - x._match.trigger[x.start..].chars().nth(0).unwrap() == c - }) - .map(|x | MatchEntry{start: x.start+1, _match: &x._match}) - .collect(); - - updated.extend(new_matches); - updated - }, - None => {new_matches}, - }; - - let mut found_match = None; - - for entry in combined_matches.iter() { - if entry.start == entry._match.trigger.len() { - found_match = Some(entry._match); - break; - } - } - - current_set_queue.push_back(combined_matches); - - if current_set_queue.len() as i32 > (self.config_manager.default_config().backspace_limit + 1) { - current_set_queue.pop_front(); - } - - if let Some(_match) = found_match { - if let Some(last) = current_set_queue.back_mut() { - last.clear(); - } - self.receiver.on_match(_match); - } - } - - fn handle_modifier(&self, m: KeyModifier) { - let config = self.config_manager.default_config(); - - if m == config.toggle_key { - let mut toggle_press_time = self.toggle_press_time.borrow_mut(); - if let Ok(elapsed) = toggle_press_time.elapsed() { - if elapsed.as_millis() < config.toggle_interval as u128 { - self.toggle(); - - let is_enabled = self.is_enabled.borrow(); - - if !*is_enabled { - self.current_set_queue.borrow_mut().clear(); - } - } - } - - (*toggle_press_time) = SystemTime::now(); - } - - // Backspace handling, basically "rewinding history" - if m == BACKSPACE { - let mut current_set_queue = self.current_set_queue.borrow_mut(); - current_set_queue.pop_back(); - } - } -} - -impl <'a, R: MatchReceiver, M: ConfigManager<'a>> ActionEventReceiver for ScrollingMatcher<'a, R, M> { - fn on_action_event(&self, e: ActionType) { - match e { - ActionType::Toggle => { - self.toggle(); - }, - ActionType::Enable => { - self.set_enabled(true); - }, - ActionType::Disable => { - self.set_enabled(false); - }, - _ => {} - } - } -} \ No newline at end of file diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs deleted file mode 100644 index 7818dce..0000000 --- a/src/protocol/mod.rs +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use serde::{Deserialize, Serialize}; -use std::sync::mpsc::Sender; -use crate::event::Event; -use crate::event::ActionType; -use std::io::{BufReader, Read, Write}; -use std::error::Error; -use log::error; -use crate::config::ConfigSet; - -#[cfg(target_os = "windows")] -mod windows; - -#[cfg(not(target_os = "windows"))] -mod unix; - -pub trait IPCServer { - fn start(&self); -} - -pub trait IPCClient { - fn send_command(&self, command: IPCCommand) -> Result<(), String>; -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct IPCCommand { - pub id: String, - - #[serde(default)] - pub payload: String, -} - -impl IPCCommand { - fn to_event(&self) -> Option { - match self.id.as_ref() { - "exit" => { - Some(Event::Action(ActionType::Exit)) - }, - "toggle" => { - Some(Event::Action(ActionType::Toggle)) - }, - "enable" => { - Some(Event::Action(ActionType::Enable)) - }, - "disable" => { - Some(Event::Action(ActionType::Disable)) - }, - _ => None - } - } -} - -fn process_event(event_channel: &Sender, stream: Result) { - match stream { - Ok(stream) => { - let mut json_str= String::new(); - let mut buf_reader = BufReader::new(stream); - let res = buf_reader.read_to_string(&mut json_str); - - if res.is_ok() { - let command : Result = serde_json::from_str(&json_str); - match command { - Ok(command) => { - let event = command.to_event(); - if let Some(event) = event { - event_channel.send(event).expect("Broken event channel"); - } - }, - Err(e) => { - error!("Error deserializing JSON command: {}", e); - }, - } - } - } - Err(err) => { - println!("Error: {}", err); - } - } -} - -fn send_command(command: IPCCommand, stream: Result) -> Result<(), String>{ - match stream { - Ok(mut stream) => { - let json_str = serde_json::to_string(&command); - if let Ok(json_str) = json_str { - stream.write_all(json_str.as_bytes()).unwrap_or_else(|e| { - println!("Can't write to IPC socket: {}", e); - }); - return Ok(()) - } - }, - Err(e) => { - return Err(format!("Can't connect to daemon: {}", e)) - } - } - - Err("Can't send command".to_owned()) -} - -// UNIX IMPLEMENTATION -#[cfg(not(target_os = "windows"))] -pub fn get_ipc_server(_: ConfigSet, event_channel: Sender) -> impl IPCServer { - unix::UnixIPCServer::new(event_channel) -} - -#[cfg(not(target_os = "windows"))] -pub fn get_ipc_client(_: ConfigSet) -> impl IPCClient { - unix::UnixIPCClient::new() -} - -// WINDOWS IMPLEMENTATION -#[cfg(target_os = "windows")] -pub fn get_ipc_server(config_set: ConfigSet, event_channel: Sender) -> impl IPCServer { - windows::WindowsIPCServer::new(config_set, event_channel) -} - -#[cfg(target_os = "windows")] -pub fn get_ipc_client(config_set: ConfigSet) -> impl IPCClient { - windows::WindowsIPCClient::new(config_set) -} \ No newline at end of file diff --git a/src/protocol/unix.rs b/src/protocol/unix.rs deleted file mode 100644 index abdb08a..0000000 --- a/src/protocol/unix.rs +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::os::unix::net::{UnixStream,UnixListener}; -use log::{info, warn}; -use std::sync::mpsc::Sender; -use super::IPCCommand; - -use crate::context; -use crate::event::*; -use crate::protocol::{process_event, send_command}; - -const UNIX_SOCKET_NAME : &str = "espanso.sock"; - -pub struct UnixIPCServer { - event_channel: Sender, -} - -impl UnixIPCServer { - pub fn new(event_channel: Sender) -> UnixIPCServer { - UnixIPCServer {event_channel} - } -} - -impl super::IPCServer for UnixIPCServer { - fn start(&self) { - let event_channel = self.event_channel.clone(); - std::thread::Builder::new().name("ipc_server".to_string()).spawn(move || { - let espanso_dir = context::get_data_dir(); - let unix_socket = espanso_dir.join(UNIX_SOCKET_NAME); - - std::fs::remove_file(unix_socket.clone()).unwrap_or_else(|e| { - warn!("Unable to delete Unix socket: {}", e); - }); - let listener = UnixListener::bind(unix_socket.clone()).expect("Can't bind to Unix Socket"); - - info!("Binded to IPC unix socket: {}", unix_socket.as_path().display()); - - for stream in listener.incoming() { - process_event(&event_channel, stream); - } - }).expect("Unable to spawn IPC server thread"); - } -} - -pub struct UnixIPCClient { - -} - -impl UnixIPCClient { - pub fn new() -> UnixIPCClient { - UnixIPCClient{} - } -} - -impl super::IPCClient for UnixIPCClient { - fn send_command(&self, command: IPCCommand) -> Result<(), String> { - let espanso_dir = context::get_data_dir(); - let unix_socket = espanso_dir.join(UNIX_SOCKET_NAME); - - // Open the stream - let stream = UnixStream::connect(unix_socket); - - send_command(command, stream) - } -} \ No newline at end of file diff --git a/src/protocol/windows.rs b/src/protocol/windows.rs deleted file mode 100644 index 8cabd30..0000000 --- a/src/protocol/windows.rs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use log::{info}; -use std::sync::mpsc::Sender; -use std::net::{TcpListener, TcpStream}; -use super::IPCCommand; - -use crate::event::*; -use crate::protocol::{process_event, send_command}; -use crate::config::ConfigSet; - -pub struct WindowsIPCServer { - config_set: ConfigSet, - event_channel: Sender, -} - -impl WindowsIPCServer { - pub fn new(config_set: ConfigSet, event_channel: Sender) -> WindowsIPCServer { - WindowsIPCServer {config_set, event_channel} - } -} - -impl super::IPCServer for WindowsIPCServer { - fn start(&self) { - let event_channel = self.event_channel.clone(); - let server_port = self.config_set.default.ipc_server_port; - std::thread::Builder::new().name("ipc_server".to_string()).spawn(move || { - let listener = TcpListener::bind( - format!("127.0.0.1:{}", server_port) - ).expect("Error binding to IPC server port"); - - info!("Binded to IPC tcp socket: {}", listener.local_addr().unwrap().to_string()); - - for stream in listener.incoming() { - process_event(&event_channel, stream); - } - }).expect("Unable to spawn IPC server thread"); - } -} - -pub struct WindowsIPCClient { - config_set: ConfigSet, -} - -impl WindowsIPCClient { - pub fn new(config_set: ConfigSet) -> WindowsIPCClient { - WindowsIPCClient{config_set} - } -} - -impl super::IPCClient for WindowsIPCClient { - fn send_command(&self, command: IPCCommand) -> Result<(), String> { - let stream = TcpStream::connect( - ("127.0.0.1", self.config_set.default.ipc_server_port as u16) - ); - - send_command(command, stream) - } -} \ No newline at end of file diff --git a/src/res/config.yaml b/src/res/config.yaml deleted file mode 100644 index af10305..0000000 --- a/src/res/config.yaml +++ /dev/null @@ -1,60 +0,0 @@ -# espanso configuration file - -# This is the default configuration file, change it as you like it -# You can refer to the official documentation: -# https://github.com/federico-terzi/espanso - -# Matches are the substitution rules, when you type the "trigger" string -# it gets replaced by the "replace" string. -matches: - # Simple text replacement - - trigger: ":espanso" - replace: "Hi there!" - - # Dates - - trigger: ":date" - replace: "{{mydate}}" - vars: - - name: mydate - type: date - params: - format: "%m/%d/%Y" - - # Shell commands - - trigger: ":shell" - replace: "{{output}}" - vars: - - name: output - type: shell - params: - cmd: "echo Hello from you shell" - - # Emojis - - trigger: ":lol" - replace: "πŸ˜‚" - - trigger: ":llol" - replace: "πŸ˜‚πŸ˜‚πŸ˜‚πŸ˜‚" - - trigger: ":sad" - replace: "☹" - - trigger: ":ssad" - replace: "☹☹☹☹" - - # Accented letters - - trigger: "e''" - replace: "Γ¨" - - trigger: "e//" - replace: "Γ©" - - trigger: "a''" - replace: "Γ " - - trigger: "i''" - replace: "Γ¬" - - trigger: "o''" - replace: "Γ²" - - trigger: "u''" - replace: "ΓΉ" - - # Capital accented letters - - trigger: "E''" - replace: "È" - - trigger: "E//" - replace: "Γ‰" \ No newline at end of file diff --git a/src/res/mac/EspansoNotifyHelper.zip b/src/res/mac/EspansoNotifyHelper.zip deleted file mode 100644 index 036ba7c..0000000 Binary files a/src/res/mac/EspansoNotifyHelper.zip and /dev/null differ diff --git a/src/res/mac/com.federicoterzi.espanso.plist b/src/res/mac/com.federicoterzi.espanso.plist deleted file mode 100644 index 0728b20..0000000 --- a/src/res/mac/com.federicoterzi.espanso.plist +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Label - com.federicoterzi.espanso - ProgramArguments - - {{{espanso_path}}} - daemon - - RunAtLoad - - StandardErrorPath - /tmp/espanso.err - StandardOutPath - /tmp/espanso.out - - \ No newline at end of file diff --git a/src/res/mac/icon.png b/src/res/mac/icon.png deleted file mode 100644 index 04d9593..0000000 Binary files a/src/res/mac/icon.png and /dev/null differ diff --git a/src/res/test/config_with_bad_yaml.yaml b/src/res/test/config_with_bad_yaml.yaml deleted file mode 100644 index b5d6822..0000000 --- a/src/res/test/config_with_bad_yaml.yaml +++ /dev/null @@ -1,12 +0,0 @@ -backend: Clipboard - -definitely a bad yaml - -matches: - # Default - - trigger: ":espanso" - replace: "Hi there!" - - # Emojis - - trigger: ":lol" - replace: "πŸ˜‚" \ No newline at end of file diff --git a/src/res/test/working_config.yaml b/src/res/test/working_config.yaml deleted file mode 100644 index bcf8bf6..0000000 --- a/src/res/test/working_config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -backend: Clipboard - -matches: - # Default - - trigger: ":espanso" - replace: "Hi there!" - - # Emojis - - trigger: ":lol" - replace: "πŸ˜‚" \ No newline at end of file diff --git a/src/res/win/espanso.bmp b/src/res/win/espanso.bmp deleted file mode 100644 index 882c849..0000000 Binary files a/src/res/win/espanso.bmp and /dev/null differ diff --git a/src/res/win/espanso.ico b/src/res/win/espanso.ico deleted file mode 100644 index 1d1c06c..0000000 Binary files a/src/res/win/espanso.ico and /dev/null differ diff --git a/src/sysdaemon.rs b/src/sysdaemon.rs deleted file mode 100644 index 2f821ec..0000000 --- a/src/sysdaemon.rs +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -// This functions are used to register/unregister espanso from the system daemon manager. - -use crate::config::ConfigSet; - -// INSTALLATION - -#[cfg(target_os = "macos")] -const MAC_PLIST_CONTENT : &str = include_str!("res/mac/com.federicoterzi.espanso.plist"); -#[cfg(target_os = "macos")] -const MAC_PLIST_FILENAME : &str = "com.federicoterzi.espanso.plist"; - -#[cfg(target_os = "macos")] -pub fn register(_config_set: ConfigSet) { - use std::fs::create_dir_all; - use std::process::{Command, ExitStatus}; - - let home_dir = dirs::home_dir().expect("Could not get user home directory"); - let library_dir = home_dir.join("Library"); - let agents_dir = library_dir.join("LaunchAgents"); - - // Make sure agents directory exists - if !agents_dir.exists() { - create_dir_all(agents_dir.clone()).expect("Could not create LaunchAgents directory"); - } - - let plist_file = agents_dir.join(MAC_PLIST_FILENAME); - if !plist_file.exists() { - println!("Creating LaunchAgents entry: {}", plist_file.to_str().unwrap_or_default()); - - let espanso_path = std::env::current_exe().expect("Could not get espanso executable path"); - println!("Entry will point to: {}", espanso_path.to_str().unwrap_or_default()); - - let plist_content = String::from(MAC_PLIST_CONTENT) - .replace("{{{espanso_path}}}", espanso_path.to_str().unwrap_or_default()); - - std::fs::write(plist_file.clone(), plist_content).expect("Unable to write plist file"); - - println!("Entry created correctly!") - } - - println!("Reloading entry..."); - - let res = Command::new("launchctl") - .args(&["unload", "-w", plist_file.to_str().unwrap_or_default()]) - .output(); - - let res = Command::new("launchctl") - .args(&["load", "-w", plist_file.to_str().unwrap_or_default()]) - .status(); - - if let Ok(status) = res { - if status.success() { - println!("Entry loaded correctly!") - } - }else{ - println!("Error loading new entry"); - } -} - -#[cfg(target_os = "macos")] -pub fn unregister(_config_set: ConfigSet) { - use std::fs::create_dir_all; - use std::process::{Command, ExitStatus}; - - let home_dir = dirs::home_dir().expect("Could not get user home directory"); - let library_dir = home_dir.join("Library"); - let agents_dir = library_dir.join("LaunchAgents"); - - let plist_file = agents_dir.join(MAC_PLIST_FILENAME); - if plist_file.exists() { - let _res = Command::new("launchctl") - .args(&["unload", "-w", plist_file.to_str().unwrap_or_default()]) - .output(); - - std::fs::remove_file(&plist_file).expect("Could not remove espanso entry"); - - println!("Entry removed correctly!") - }else{ - println!("espanso is not installed"); - } -} - -// LINUX - -#[cfg(target_os = "linux")] -pub fn register(config_set: ConfigSet) { - println!("Linux does not support automatic system daemon integration."); -} - -#[cfg(target_os = "linux")] -pub fn unregister(config_set: ConfigSet) { - println!("Linux does not support automatic system daemon integration."); -} - -// WINDOWS - -#[cfg(target_os = "windows")] -pub fn register(_config_set: ConfigSet) { - println!("Windows does not support automatic system daemon integration.") -} - -#[cfg(target_os = "windows")] -pub fn unregister(_config_set: ConfigSet) { - println!("Windows does not support automatic system daemon integration.") -} \ No newline at end of file diff --git a/src/system/linux.rs b/src/system/linux.rs deleted file mode 100644 index df05ac3..0000000 --- a/src/system/linux.rs +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::os::raw::c_char; - -use crate::bridge::linux::{get_active_window_name, get_active_window_class, get_active_window_executable}; -use std::ffi::CStr; - -pub struct LinuxSystemManager {} - -impl super::SystemManager for LinuxSystemManager { - fn get_current_window_title(&self) -> Option { - unsafe { - let mut buffer : [c_char; 100] = [0; 100]; - let res = get_active_window_name(buffer.as_mut_ptr(), buffer.len() as i32); - - if res > 0 { - let c_string = CStr::from_ptr(buffer.as_ptr()); - - let string = c_string.to_str(); - if let Ok(string) = string { - return Some((*string).to_owned()); - } - } - } - - None - } - - fn get_current_window_class(&self) -> Option { - unsafe { - let mut buffer : [c_char; 100] = [0; 100]; - let res = get_active_window_class(buffer.as_mut_ptr(), buffer.len() as i32); - - if res > 0 { - let c_string = CStr::from_ptr(buffer.as_ptr()); - - let string = c_string.to_str(); - if let Ok(string) = string { - return Some((*string).to_owned()); - } - } - } - - None - } - - fn get_current_window_executable(&self) -> Option { - unsafe { - let mut buffer : [c_char; 100] = [0; 100]; - let res = get_active_window_executable(buffer.as_mut_ptr(), buffer.len() as i32); - - if res > 0 { - let c_string = CStr::from_ptr(buffer.as_ptr()); - - let string = c_string.to_str(); - if let Ok(string) = string { - return Some((*string).to_owned()); - } - } - } - - None - } -} - -impl LinuxSystemManager { - pub fn new() -> LinuxSystemManager { - LinuxSystemManager{} - } -} \ No newline at end of file diff --git a/src/system/macos.rs b/src/system/macos.rs deleted file mode 100644 index fc867d1..0000000 --- a/src/system/macos.rs +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::os::raw::c_char; - -use std::ffi::CStr; -use crate::bridge::macos::{get_active_app_bundle, get_active_app_identifier}; - -pub struct MacSystemManager { - -} - -impl super::SystemManager for MacSystemManager { - fn get_current_window_title(&self) -> Option { - self.get_current_window_class() - } - - fn get_current_window_class(&self) -> Option { - unsafe { - let mut buffer : [c_char; 250] = [0; 250]; - let res = get_active_app_identifier(buffer.as_mut_ptr(), buffer.len() as i32); - - if res > 0 { - let c_string = CStr::from_ptr(buffer.as_ptr()); - - let string = c_string.to_str(); - if let Ok(string) = string { - return Some((*string).to_owned()); - } - } - } - - None - } - - fn get_current_window_executable(&self) -> Option { - unsafe { - let mut buffer : [c_char; 250] = [0; 250]; - let res = get_active_app_bundle(buffer.as_mut_ptr(), buffer.len() as i32); - - if res > 0 { - let c_string = CStr::from_ptr(buffer.as_ptr()); - - let string = c_string.to_str(); - if let Ok(string) = string { - return Some((*string).to_owned()); - } - } - } - - None - } -} - -impl MacSystemManager { - pub fn new() -> MacSystemManager { - MacSystemManager{ - - } - } -} \ No newline at end of file diff --git a/src/system/mod.rs b/src/system/mod.rs deleted file mode 100644 index fadcf5a..0000000 --- a/src/system/mod.rs +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#[cfg(target_os = "windows")] -mod windows; - -#[cfg(target_os = "linux")] -mod linux; - -#[cfg(target_os = "macos")] -mod macos; - -pub trait SystemManager { - fn get_current_window_title(&self) -> Option; - fn get_current_window_class(&self) -> Option; - fn get_current_window_executable(&self) -> Option; -} - -// LINUX IMPLEMENTATION -#[cfg(target_os = "linux")] -pub fn get_manager() -> impl SystemManager { - linux::LinuxSystemManager::new() -} - -// WINDOWS IMPLEMENTATION -#[cfg(target_os = "windows")] -pub fn get_manager() -> impl SystemManager { - windows::WindowsSystemManager::new() -} - -// MAC IMPLEMENTATION -#[cfg(target_os = "macos")] -pub fn get_manager() -> impl SystemManager { - macos::MacSystemManager::new() -} \ No newline at end of file diff --git a/src/system/windows.rs b/src/system/windows.rs deleted file mode 100644 index 01e9cfd..0000000 --- a/src/system/windows.rs +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use widestring::U16CString; -use crate::bridge::windows::*; - -pub struct WindowsSystemManager { - -} - -impl WindowsSystemManager { - pub fn new() -> WindowsSystemManager { - WindowsSystemManager{} - } -} - -impl super::SystemManager for WindowsSystemManager { - fn get_current_window_title(&self) -> Option { - unsafe { - let mut buffer : [u16; 100] = [0; 100]; - let res = get_active_window_name(buffer.as_mut_ptr(), buffer.len() as i32); - - if res > 0 { - let c_string = U16CString::from_ptr_str(buffer.as_ptr()); - - let string = c_string.to_string_lossy(); - return Some((*string).to_owned()); - } - } - - None - } - - fn get_current_window_class(&self) -> Option { - self.get_current_window_executable() - } - - fn get_current_window_executable(&self) -> Option { - unsafe { - let mut buffer : [u16; 250] = [0; 250]; - let res = get_active_window_executable(buffer.as_mut_ptr(), buffer.len() as i32); - - if res > 0 { - let c_string = U16CString::from_ptr_str(buffer.as_ptr()); - - let string = c_string.to_string_lossy(); - return Some((*string).to_owned()); - } - } - - None - } -} \ No newline at end of file diff --git a/src/ui/linux.rs b/src/ui/linux.rs deleted file mode 100644 index de8ac81..0000000 --- a/src/ui/linux.rs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::process::Command; -use super::MenuItem; -use log::error; - -pub struct LinuxUIManager {} - -impl super::UIManager for LinuxUIManager { - fn notify(&self, message: &str) { - let res = Command::new("notify-send") - .args(&["-t", "2000", "espanso", message]) - .output(); - - if let Err(e) = res { - error!("Could not send a notification, error: {}", e); - } - } - - fn show_menu(&self, _menu: Vec) { - // Not implemented on linux - } - - fn cleanup(&self) { - // Nothing to do here - } -} - -impl LinuxUIManager { - pub fn new() -> LinuxUIManager { - LinuxUIManager{} - } -} \ No newline at end of file diff --git a/src/ui/macos.rs b/src/ui/macos.rs deleted file mode 100644 index 8bcf791..0000000 --- a/src/ui/macos.rs +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use std::{fs, io}; -use std::io::{Cursor}; -use std::ffi::CString; -use log::{info, warn, debug}; -use std::path::PathBuf; -use std::process::Command; -use crate::ui::{MenuItem, MenuItemType}; -use crate::bridge::macos::{MacMenuItem, show_context_menu}; -use std::os::raw::c_char; -use crate::context; - -const NOTIFY_HELPER_BINARY : &'static [u8] = include_bytes!("../res/mac/EspansoNotifyHelper.zip"); -const DEFAULT_NOTIFICATION_DELAY : f64 = 1.5; - -pub struct MacUIManager { - notify_helper_path: PathBuf -} - -impl super::UIManager for MacUIManager { - fn notify(&self, message: &str) { - let executable_path = self.notify_helper_path.join("Contents"); - let executable_path = executable_path.join("MacOS"); - let executable_path = executable_path.join("EspansoNotifyHelper"); - - let res = Command::new(executable_path) - .args(&["espanso", message, &DEFAULT_NOTIFICATION_DELAY.to_string()]) - .spawn(); - - if let Err(e) = res { - warn!("Error while dispatching Notify Helper {}", e) - } - } - - fn show_menu(&self, menu: Vec) { - let mut raw_menu = Vec::new(); - - for item in menu.iter() { - let text = CString::new(item.item_name.clone()).unwrap_or_default(); - let mut str_buff : [c_char; 100] = [0; 100]; - unsafe { - std::ptr::copy(text.as_ptr(), str_buff.as_mut_ptr(), item.item_name.len()); - } - - let menu_type = match item.item_type { - MenuItemType::Button => {1}, - MenuItemType::Separator => {2}, - }; - - let raw_item = MacMenuItem { - item_id: item.item_id, - item_type: menu_type, - item_name: str_buff, - }; - - raw_menu.push(raw_item); - } - - unsafe { show_context_menu(raw_menu.as_ptr(), raw_menu.len() as i32); } - } - - fn cleanup(&self) { - // Nothing to do here - } -} - -impl MacUIManager { - pub fn new() -> MacUIManager { - let notify_helper_path = MacUIManager::initialize_notify_helper(); - - MacUIManager{ - notify_helper_path - } - } - - fn initialize_notify_helper() -> PathBuf { - let espanso_dir = context::get_data_dir(); - - info!("Initializing EspansoNotifyHelper in {}", espanso_dir.as_path().display()); - - let espanso_target = espanso_dir.join("EspansoNotifyHelper.app"); - - if espanso_target.exists() { - info!("EspansoNotifyHelper already initialized, skipping."); - }else{ - // Extract zip file - let reader = Cursor::new(NOTIFY_HELPER_BINARY); - - let mut archive = zip::ZipArchive::new(reader).unwrap(); - - for i in 0..archive.len() { - let mut file = archive.by_index(i).unwrap(); - let outpath = espanso_dir.join(file.sanitized_name()); - - { - let comment = file.comment(); - if !comment.is_empty() { - debug!("File {} comment: {}", i, comment); - } - } - - if (&*file.name()).ends_with('/') { - debug!("File {} extracted to \"{}\"", i, outpath.as_path().display()); - fs::create_dir_all(&outpath).unwrap(); - } else { - debug!("File {} extracted to \"{}\" ({} bytes)", i, outpath.as_path().display(), file.size()); - if let Some(p) = outpath.parent() { - if !p.exists() { - fs::create_dir_all(&p).unwrap(); - } - } - let mut outfile = fs::File::create(&outpath).unwrap(); - io::copy(&mut file, &mut outfile).unwrap(); - } - - use std::os::unix::fs::PermissionsExt; - - if let Some(mode) = file.unix_mode() { - fs::set_permissions(&outpath, fs::Permissions::from_mode(mode)).unwrap(); - } - } - } - - espanso_target - } -} \ No newline at end of file diff --git a/src/ui/mod.rs b/src/ui/mod.rs deleted file mode 100644 index 1b096c6..0000000 --- a/src/ui/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -#[cfg(target_os = "windows")] -mod windows; - -#[cfg(target_os = "linux")] -mod linux; - -#[cfg(target_os = "macos")] -mod macos; - -pub trait UIManager { - fn notify(&self, message: &str); - fn show_menu(&self, menu: Vec); - fn cleanup(&self); -} - -pub enum MenuItemType { - Button, - Separator, -} - -pub struct MenuItem { - pub item_id: i32, - pub item_type: MenuItemType, - pub item_name: String, -} - -// MAC IMPLEMENTATION -#[cfg(target_os = "macos")] -pub fn get_uimanager() -> impl UIManager { - macos::MacUIManager::new() -} - -// LINUX IMPLEMENTATION -#[cfg(target_os = "linux")] -pub fn get_uimanager() -> impl UIManager { - linux::LinuxUIManager::new() -} - -// WINDOWS IMPLEMENTATION -#[cfg(target_os = "windows")] -pub fn get_uimanager() -> impl UIManager { - windows::WindowsUIManager::new() -} \ No newline at end of file diff --git a/src/ui/windows.rs b/src/ui/windows.rs deleted file mode 100644 index 4024939..0000000 --- a/src/ui/windows.rs +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of espanso. - * - * Copyright (C) 2019 Federico Terzi - * - * espanso is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * espanso is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with espanso. If not, see . - */ - -use crate::bridge::windows::{show_notification, close_notification, WindowsMenuItem, show_context_menu, cleanup_ui}; -use widestring::U16CString; -use std::{thread, time}; -use log::{debug}; -use std::sync::Mutex; -use std::sync::Arc; -use crate::ui::{MenuItem, MenuItemType}; - -pub struct WindowsUIManager { - id: Arc> -} - -impl super::UIManager for WindowsUIManager { - fn notify(&self, message: &str) { - let current_id: i32 = { - let mut id = self.id.lock().unwrap(); - *id += 1; - *id - }; - - // Setup a timeout to close the notification - let id = Arc::clone(&self.id); - let _ = thread::Builder::new().name("notification_thread".to_string()).spawn(move || { - for _ in 1..10 { - let duration = time::Duration::from_millis(200); - thread::sleep(duration); - - let new_id = id.lock().unwrap(); - if *new_id != current_id { - debug!("Cancelling notification close event with id {}", current_id); - return; - } - } - - unsafe { - close_notification(); - } - }); - - // Create and show a window notification - unsafe { - let message = U16CString::from_str(message).unwrap(); - show_notification(message.as_ptr()); - } - - } - - fn show_menu(&self, menu: Vec) { - let mut raw_menu = Vec::new(); - - for item in menu.iter() { - let text = U16CString::from_str(item.item_name.clone()).unwrap_or_default(); - let mut str_buff : [u16; 100] = [0; 100]; - unsafe { - std::ptr::copy(text.as_ptr(), str_buff.as_mut_ptr(), text.len()); - } - - let menu_type = match item.item_type { - MenuItemType::Button => {1}, - MenuItemType::Separator => {2}, - }; - - let raw_item = WindowsMenuItem { - item_id: item.item_id, - item_type: menu_type, - item_name: str_buff, - }; - - raw_menu.push(raw_item); - } - - unsafe { show_context_menu(raw_menu.as_ptr(), raw_menu.len() as i32); } - } - - fn cleanup(&self) { - unsafe { - cleanup_ui(); - } - } -} - -impl WindowsUIManager { - pub fn new() -> WindowsUIManager { - let id = Arc::new(Mutex::new(0)); - - let manager = WindowsUIManager { - id - }; - - manager - } -} \ No newline at end of file