Refinement, plugins, etc.

This commit is contained in:
Kirottu
2022-12-31 12:51:46 +02:00
parent 990bf12b79
commit ce4b157160
17 changed files with 36037 additions and 223 deletions

699
Cargo.lock generated
View File

@@ -50,6 +50,15 @@ dependencies = [
"core_extensions", "core_extensions",
] ]
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.68" version = "1.0.68"
@@ -64,8 +73,10 @@ dependencies = [
"anyrun-interface", "anyrun-interface",
"gtk", "gtk",
"gtk-layer-shell", "gtk-layer-shell",
"nix 0.26.1",
"ron", "ron",
"serde", "serde",
"wl-clipboard-rs",
] ]
[[package]] [[package]]
@@ -89,6 +100,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"abi_stable", "abi_stable",
"anyrun-plugin", "anyrun-plugin",
"fuzzy-matcher",
"sublime_fuzzy", "sublime_fuzzy",
] ]
@@ -146,6 +158,18 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
[[package]]
name = "bytecount"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
[[package]] [[package]]
name = "cairo-rs" name = "cairo-rs"
version = "0.16.7" version = "0.16.7"
@@ -171,6 +195,12 @@ dependencies = [
"system-deps", "system-deps",
] ]
[[package]]
name = "cc"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]] [[package]]
name = "cfg-expr" name = "cfg-expr"
version = "0.11.0" version = "0.11.0"
@@ -192,12 +222,62 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
dependencies = [
"iana-time-zone",
"js-sys",
"num-integer",
"num-traits",
"time",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "chrono-humanize"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8164ae3089baf04ff71f32aeb70213283dcd236dce8bc976d00b17a458f5f71c"
dependencies = [
"chrono",
]
[[package]]
name = "chrono-tz"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2554a3155fec064362507487171dcc4edc3df60cb10f3a1fb10ed8094822b120"
dependencies = [
"chrono",
"parse-zoneinfo",
]
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]] [[package]]
name = "const_panic" name = "const_panic"
version = "0.2.7" version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58baae561b85ca19b3122a9ddd35c8ec40c3bcd14fe89921824eae73f7baffbf" checksum = "58baae561b85ca19b3122a9ddd35c8ec40c3bcd14fe89921824eae73f7baffbf"
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]] [[package]]
name = "core_extensions" name = "core_extensions"
version = "1.5.3" version = "1.5.3"
@@ -232,6 +312,76 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
[[package]]
name = "cxx"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd"
dependencies = [
"cc",
"cxxbridge-flags",
"cxxbridge-macro",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0"
dependencies = [
"cc",
"codespan-reporting",
"once_cell",
"proc-macro2",
"quote",
"scratch",
"syn",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59"
[[package]]
name = "cxxbridge-macro"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive-new"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "downcast-rs"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "fastrand"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
dependencies = [
"instant",
]
[[package]] [[package]]
name = "field-offset" name = "field-offset"
version = "0.3.4" version = "0.3.4"
@@ -242,6 +392,18 @@ dependencies = [
"rustc_version 0.3.3", "rustc_version 0.3.3",
] ]
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.25" version = "0.3.25"
@@ -305,6 +467,15 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "fuzzy-matcher"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
dependencies = [
"thread_local",
]
[[package]] [[package]]
name = "gdk" name = "gdk"
version = "0.16.2" version = "0.16.2"
@@ -547,18 +718,82 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "iana-time-zone"
version = "0.1.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"winapi",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
dependencies = [
"cxx",
"cxx-build",
]
[[package]]
name = "indexmap"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.5" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "js-sys"
version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.139" version = "0.2.139"
@@ -575,6 +810,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "link-cplusplus"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.9" version = "0.4.9"
@@ -585,6 +829,21 @@ dependencies = [
"scopeguard", "scopeguard",
] ]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.6.5" version = "0.6.5"
@@ -594,12 +853,141 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nix"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
"libc",
"memoffset",
]
[[package]]
name = "nix"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
"libc",
"static_assertions",
]
[[package]]
name = "nom"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "num-complex"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
dependencies = [
"num-traits",
"serde",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.16.0" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "os_pipe"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6a252f1f8c11e84b3ab59d7a488e48e4478a93937e027076638c49536204639"
dependencies = [
"libc",
"windows-sys",
]
[[package]] [[package]]
name = "pango" name = "pango"
version = "0.16.5" version = "0.16.5"
@@ -649,6 +1037,15 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "parse-zoneinfo"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41"
dependencies = [
"regex",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.11" version = "1.0.11"
@@ -665,6 +1062,16 @@ dependencies = [
"ucd-trie", "ucd-trie",
] ]
[[package]]
name = "petgraph"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.9"
@@ -745,6 +1152,30 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "regex"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "repr_offset" name = "repr_offset"
version = "0.2.1" version = "0.2.1"
@@ -754,6 +1185,30 @@ dependencies = [
"tstr", "tstr",
] ]
[[package]]
name = "rink"
version = "0.1.0"
dependencies = [
"abi_stable",
"anyrun-plugin",
"rink-core",
]
[[package]]
name = "rink-core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f583576891114abaf8e057cc86f4f59a1835e1511877a96c3b4a2e0719f60b9"
dependencies = [
"chrono",
"chrono-humanize",
"chrono-tz",
"num",
"serde",
"serde_derive",
"strsim",
]
[[package]] [[package]]
name = "ron" name = "ron"
version = "0.8.0" version = "0.8.0"
@@ -795,6 +1250,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scratch"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
[[package]] [[package]]
name = "semver" name = "semver"
version = "0.11.0" version = "0.11.0"
@@ -821,18 +1282,18 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.151" version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.151" version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -865,6 +1326,18 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "sublime_fuzzy" name = "sublime_fuzzy"
version = "0.7.0" version = "0.7.0"
@@ -877,6 +1350,9 @@ version = "0.1.0"
dependencies = [ dependencies = [
"abi_stable", "abi_stable",
"anyrun-plugin", "anyrun-plugin",
"fuzzy-matcher",
"ron",
"serde",
] ]
[[package]] [[package]]
@@ -903,6 +1379,29 @@ dependencies = [
"version-compare", "version-compare",
] ]
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if 1.0.0",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.38" version = "1.0.38"
@@ -923,6 +1422,26 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thread_local"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi",
"winapi",
]
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.5.10" version = "0.5.10"
@@ -932,6 +1451,20 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "tree_magic_mini"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91adfd0607cacf6e4babdb870e9bec4037c1c4b151cfd279ccefc5e0c7feaa6d"
dependencies = [
"bytecount",
"fnv",
"lazy_static",
"nom",
"once_cell",
"petgraph",
]
[[package]] [[package]]
name = "tstr" name = "tstr"
version = "0.2.3" version = "0.2.3"
@@ -965,6 +1498,12 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]] [[package]]
name = "version-compare" name = "version-compare"
version = "0.1.1" version = "0.1.1"
@@ -978,11 +1517,122 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "web-search" name = "wasi"
version = "0.1.0" version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasm-bindgen"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
dependencies = [ dependencies = [
"abi_stable", "cfg-if 1.0.0",
"anyrun-plugin", "wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]]
name = "wayland-client"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715"
dependencies = [
"bitflags",
"downcast-rs",
"libc",
"nix 0.24.3",
"wayland-commons",
"wayland-scanner",
"wayland-sys",
]
[[package]]
name = "wayland-commons"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902"
dependencies = [
"nix 0.24.3",
"once_cell",
"smallvec",
"wayland-sys",
]
[[package]]
name = "wayland-protocols"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
dependencies = [
"bitflags",
"wayland-client",
"wayland-commons",
"wayland-scanner",
]
[[package]]
name = "wayland-scanner"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
dependencies = [
"proc-macro2",
"quote",
"xml-rs",
]
[[package]]
name = "wayland-sys"
version = "0.29.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4"
dependencies = [
"pkg-config",
] ]
[[package]] [[package]]
@@ -1001,6 +1651,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
@@ -1063,3 +1722,27 @@ name = "windows_x86_64_msvc"
version = "0.42.0" version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "wl-clipboard-rs"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "981a303dfbb75d659f6612d05a14b2e363c103d24f676a2d44a00d18507a1ad9"
dependencies = [
"derive-new",
"libc",
"log",
"nix 0.24.3",
"os_pipe",
"tempfile",
"thiserror",
"tree_magic_mini",
"wayland-client",
"wayland-protocols",
]
[[package]]
name = "xml-rs"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"

View File

@@ -5,5 +5,5 @@ members = [
"anyrun-interface", "anyrun-interface",
"plugins/applications", "plugins/applications",
"plugins/symbols", "plugins/symbols",
"plugins/web-search", "plugins/rink",
] ]

5
README.md Normal file
View File

@@ -0,0 +1,5 @@
# AnyRun
A wayland native krunner-like runner, made with customizability in mind.

View File

@@ -29,15 +29,18 @@ pub struct PluginInfo {
} }
/// Represents a match from a plugin /// Represents a match from a plugin
///
/// The `title` and `description` support pango markup.
/// Refer to [Pango Markup](https://docs.gtk.org/Pango/pango_markup.html) for how to use pango markup.
#[repr(C)] #[repr(C)]
#[derive(StableAbi, Clone)] #[derive(StableAbi, Clone)]
pub struct Match { pub struct Match {
pub title: RString, pub title: RString,
pub description: ROption<RString>, pub description: ROption<RString>,
/// The icon name from the icon theme in use /// The icon name from the icon theme in use
pub icon: RString, pub icon: ROption<RString>,
/// For runners to differentiate between the matches. /// For runners to differentiate between the matches. Not required.
pub id: u64, pub id: ROption<u64>,
} }
/// For determining how anyrun should proceed after the plugin has handled a match selection /// For determining how anyrun should proceed after the plugin has handled a match selection
@@ -48,6 +51,8 @@ pub enum HandleResult {
Close, Close,
/// Refresh the items. Useful if the runner wants to alter results in place. /// Refresh the items. Useful if the runner wants to alter results in place.
Refresh, Refresh,
/// Copy the content, due to how copying works it must be done like this.
Copy(RVec<u8>),
} }
#[repr(C)] #[repr(C)]

View File

@@ -6,9 +6,8 @@ for integrating with `stable_abi`.
# Arguments # Arguments
* `$init`: Function that takes an `RString` as the only argument, which points to the anyrun config directory. It returns nothing. * `$init`: Function that takes an `RString` as the only argument, which points to the anyrun config directory. Returns the data
The path is used for plugin specific config files. the plugin operates on.
**NOTE**: Should not block or block for a long time. If this blocks the main thread will too.
* `$info`: Function that returns the plugin info as a `PluginInfo` object. Takes no arguments. * `$info`: Function that returns the plugin info as a `PluginInfo` object. Takes no arguments.
@@ -17,85 +16,100 @@ This is run asynchronously automatically.
* `$handler`: The function to handle the selection of an item. Takes a `Match` as it's only argument and returns a `HandleResult` with * `$handler`: The function to handle the selection of an item. Takes a `Match` as it's only argument and returns a `HandleResult` with
the appropriate action. the appropriate action.
* `$type`: The type of the shared data to be provided to various functions.
**/ **/
#[macro_export] #[macro_export]
macro_rules! plugin { macro_rules! plugin {
($init:ident, $info:ident, $get_matches:ident, $handler:ident) => { ($init:ident, $info:ident, $get_matches:ident, $handler:ident, $type:ty) => {
mod anyrun_plugin_internal { static ANYRUN_INTERNAL_THREAD: ::std::sync::Mutex<
static THREAD: ::std::sync::Mutex< Option<(
Option<( ::std::thread::JoinHandle<
::std::thread::JoinHandle< ::abi_stable::std_types::RVec<::anyrun_plugin::anyrun_interface::Match>,
::abi_stable::std_types::RVec<::anyrun_plugin::anyrun_interface::Match>, >,
>, u64,
u64, )>,
)>, > = ::std::sync::Mutex::new(None);
> = ::std::sync::Mutex::new(None); static ANYRUN_INTERNAL_ID_COUNTER: ::std::sync::atomic::AtomicU64 =
static ID_COUNTER: ::std::sync::atomic::AtomicU64 = ::std::sync::atomic::AtomicU64::new(0);
::std::sync::atomic::AtomicU64::new(0); static ANYRUN_INTERNAL_DATA: ::std::sync::Mutex<Option<$type>> =
::std::sync::Mutex::new(None);
#[::abi_stable::export_root_module] #[::abi_stable::export_root_module]
fn init_root_module() -> ::anyrun_plugin::anyrun_interface::PluginRef { fn anyrun_internal_init_root_module() -> ::anyrun_plugin::anyrun_interface::PluginRef {
use ::abi_stable::prefix_type::PrefixTypeTrait; use ::abi_stable::prefix_type::PrefixTypeTrait;
::anyrun_plugin::anyrun_interface::Plugin { ::anyrun_plugin::anyrun_interface::Plugin {
init, init: anyrun_internal_init,
info, info: anyrun_internal_info,
get_matches, get_matches: anyrun_internal_get_matches,
poll_matches, poll_matches: anyrun_internal_poll_matches,
handle_selection, handle_selection: anyrun_internal_handle_selection,
}
.leak_into_prefix()
}
#[::abi_stable::sabi_extern_fn]
fn anyrun_internal_init(config_dir: ::abi_stable::std_types::RString) {
::std::thread::spawn(|| {
*ANYRUN_INTERNAL_DATA.lock().unwrap() = Some($init(config_dir));
});
}
#[::abi_stable::sabi_extern_fn]
fn anyrun_internal_info() -> ::anyrun_plugin::anyrun_interface::PluginInfo {
$info()
}
#[::abi_stable::sabi_extern_fn]
fn anyrun_internal_get_matches(input: ::abi_stable::std_types::RString) -> u64 {
let current_id =
ANYRUN_INTERNAL_ID_COUNTER.load(::std::sync::atomic::Ordering::Relaxed);
ANYRUN_INTERNAL_ID_COUNTER
.store(current_id + 1, ::std::sync::atomic::Ordering::Relaxed);
let handle = ::std::thread::spawn(move || {
if let Some(data) = ANYRUN_INTERNAL_DATA.lock().unwrap().as_mut() {
$get_matches(input, data)
} else {
::abi_stable::std_types::RVec::new()
} }
.leak_into_prefix() });
}
#[::abi_stable::sabi_extern_fn] *ANYRUN_INTERNAL_THREAD.lock().unwrap() = Some((handle, current_id));
fn init(config_dir: ::abi_stable::std_types::RString) {
super::$init(config_dir);
}
#[::abi_stable::sabi_extern_fn] current_id
fn info() -> ::anyrun_plugin::anyrun_interface::PluginInfo { }
super::$info()
}
#[::abi_stable::sabi_extern_fn] #[::abi_stable::sabi_extern_fn]
fn get_matches(input: ::abi_stable::std_types::RString) -> u64 { fn anyrun_internal_poll_matches(id: u64) -> ::anyrun_plugin::anyrun_interface::PollResult {
let current_id = ID_COUNTER.load(::std::sync::atomic::Ordering::Relaxed); match ANYRUN_INTERNAL_THREAD.try_lock() {
ID_COUNTER.store(current_id + 1, ::std::sync::atomic::Ordering::Relaxed); Ok(thread) => match thread.as_ref() {
Some((thread, task_id)) => {
let handle = ::std::thread::spawn(move || super::$get_matches(input)); if *task_id == id {
if !thread.is_finished() {
*THREAD.lock().unwrap() = Some((handle, current_id)); return ::anyrun_plugin::anyrun_interface::PollResult::Pending;
current_id
}
#[::abi_stable::sabi_extern_fn]
fn poll_matches(id: u64) -> ::anyrun_plugin::anyrun_interface::PollResult {
match THREAD.try_lock() {
Ok(thread) => match thread.as_ref() {
Some((thread, task_id)) => {
if *task_id == id {
if !thread.is_finished() {
return ::anyrun_plugin::anyrun_interface::PollResult::Pending;
}
} else {
return ::anyrun_plugin::anyrun_interface::PollResult::Cancelled;
} }
} else {
return ::anyrun_plugin::anyrun_interface::PollResult::Cancelled;
} }
None => return ::anyrun_plugin::anyrun_interface::PollResult::Cancelled, }
}, None => return ::anyrun_plugin::anyrun_interface::PollResult::Cancelled,
Err(_) => return ::anyrun_plugin::anyrun_interface::PollResult::Pending, },
} Err(_) => return ::anyrun_plugin::anyrun_interface::PollResult::Pending,
let (thread, _) = THREAD.lock().unwrap().take().unwrap();
::anyrun_plugin::anyrun_interface::PollResult::Ready(thread.join().unwrap())
} }
#[::abi_stable::sabi_extern_fn] let (thread, _) = ANYRUN_INTERNAL_THREAD.lock().unwrap().take().unwrap();
fn handle_selection( ::anyrun_plugin::anyrun_interface::PollResult::Ready(thread.join().unwrap())
selection: ::anyrun_plugin::anyrun_interface::Match, }
) -> ::anyrun_plugin::anyrun_interface::HandleResult {
super::$handler(selection) #[::abi_stable::sabi_extern_fn]
} fn anyrun_internal_handle_selection(
selection: ::anyrun_plugin::anyrun_interface::Match,
) -> ::anyrun_plugin::anyrun_interface::HandleResult {
$handler(
selection,
ANYRUN_INTERNAL_DATA.lock().unwrap().as_mut().unwrap(),
)
} }
}; };
} }

View File

@@ -12,3 +12,5 @@ gtk-layer-shell = { version = "0.5.0", features = ["v0_6"] }
ron = "0.8.0" ron = "0.8.0"
serde = { version = "1.0.151", features = ["derive"] } serde = { version = "1.0.151", features = ["derive"] }
anyrun-interface = { path = "../anyrun-interface" } anyrun-interface = { path = "../anyrun-interface" }
wl-clipboard-rs = "0.7.0"
nix = { version = "0.26.1", default-features = false, features = ["process"] }

View File

@@ -1,15 +1,11 @@
use std::{ use std::{cell::RefCell, env, fs, path::PathBuf, rc::Rc, time::Duration};
cell::RefCell,
env, fs,
path::{Path, PathBuf},
rc::Rc,
time::Duration,
};
use abi_stable::std_types::{ROption, RVec}; use abi_stable::std_types::{ROption, RVec};
use gtk::{gdk, glib, prelude::*};
use serde::Deserialize;
use anyrun_interface::{HandleResult, Match, PluginInfo, PluginRef, PollResult}; use anyrun_interface::{HandleResult, Match, PluginInfo, PluginRef, PollResult};
use gtk::{gdk, glib, prelude::*};
use nix::unistd;
use serde::Deserialize;
use wl_clipboard_rs::copy;
#[derive(Deserialize)] #[derive(Deserialize)]
struct Config { struct Config {
@@ -17,6 +13,7 @@ struct Config {
plugins: Vec<PathBuf>, plugins: Vec<PathBuf>,
} }
/// A "view" of plugin's info and matches
#[derive(Clone)] #[derive(Clone)]
struct PluginView { struct PluginView {
plugin: PluginRef, plugin: PluginRef,
@@ -29,11 +26,32 @@ struct Args {
config_dir: Option<String>, config_dir: Option<String>,
} }
/// Actions to run after GTK has finished
enum PostRunAction {
Copy(Vec<u8>),
None,
}
/// Some data that needs to be shared between various parts
struct RuntimeData {
args: Args,
post_run_action: PostRunAction,
}
/// The naming scheme for CSS styling
///
/// Refer to [GTK 3.0 CSS Overview](https://docs.gtk.org/gtk3/css-overview.html)
/// and [GTK 3.0 CSS Properties](https://docs.gtk.org/gtk3/css-properties.html) for how to style.
mod style_names { mod style_names {
/// The text entry box
pub const ENTRY: &str = "entry"; pub const ENTRY: &str = "entry";
/// "Main" widgets (main GtkListBox, main GtkBox)
pub const MAIN: &str = "main"; pub const MAIN: &str = "main";
/// The window
pub const WINDOW: &str = "window"; pub const WINDOW: &str = "window";
/// Widgets related to the whole plugin. Including the info box
pub const PLUGIN: &str = "plugin"; pub const PLUGIN: &str = "plugin";
/// Widgets for the specific match `MATCH_*` names are for more specific parts.
pub const MATCH: &str = "match"; pub const MATCH: &str = "match";
pub const MATCH_TITLE: &str = "match-title"; pub const MATCH_TITLE: &str = "match-title";
@@ -43,8 +61,9 @@ mod style_names {
fn main() { fn main() {
let app = gtk::Application::new(Some("com.kirottu.anyrun"), Default::default()); let app = gtk::Application::new(Some("com.kirottu.anyrun"), Default::default());
let args: Rc<RefCell<Option<Args>>> = Rc::new(RefCell::new(None)); let runtime_data: Rc<RefCell<Option<RuntimeData>>> = Rc::new(RefCell::new(None));
// Add the launch options to the GTK Application
app.add_main_option( app.add_main_option(
"override-plugins", "override-plugins",
glib::Char('o' as i8), glib::Char('o' as i8),
@@ -62,30 +81,60 @@ fn main() {
None, None,
); );
let args_clone = args.clone(); let runtime_data_clone = runtime_data.clone();
app.connect_handle_local_options(move |_app, dict| { app.connect_handle_local_options(move |_app, dict| {
let override_plugins = dict.lookup::<Vec<String>>("override-plugins").unwrap(); let override_plugins = dict.lookup::<Vec<String>>("override-plugins").unwrap();
let config_dir = dict.lookup::<String>("config-dir").unwrap(); let config_dir = dict.lookup::<String>("config-dir").unwrap();
*args_clone.borrow_mut() = Some(Args { *runtime_data_clone.borrow_mut() = Some(RuntimeData {
override_plugins, args: Args {
config_dir, override_plugins,
config_dir,
},
post_run_action: PostRunAction::None,
}); });
-1 // Magic GTK number to continue running -1 // Magic GTK number to continue running
}); });
let args_clone = args.clone(); let runtime_data_clone = runtime_data.clone();
app.connect_activate(move |app| activate(app, args_clone.clone())); app.connect_activate(move |app| activate(app, runtime_data_clone.clone()));
app.run(); app.run();
let runtime_data = runtime_data.borrow_mut().take().unwrap();
// Perform a post run action if one is set
match runtime_data.post_run_action {
PostRunAction::Copy(bytes) => match unsafe { unistd::fork() } {
// The parent process just exits and prints that out
Ok(unistd::ForkResult::Parent { .. }) => {
println!("Child spawned to serve copy requests.");
}
// Child process starts serving copy requests
Ok(unistd::ForkResult::Child) => {
let mut opts = copy::Options::new();
opts.foreground(true);
opts.copy(
copy::Source::Bytes(bytes.into_boxed_slice()),
copy::MimeType::Autodetect,
)
.expect("Failed to serve copy bytes");
}
Err(why) => {
println!("Failed to fork for copy sharing: {}", why);
}
},
PostRunAction::None => (),
}
} }
fn activate(app: &gtk::Application, args: Rc<RefCell<Option<Args>>>) { fn activate(app: &gtk::Application, runtime_data: Rc<RefCell<Option<RuntimeData>>>) {
// Figure out the config dir // Figure out the config dir
let config_dir = args let config_dir = runtime_data
.borrow() .borrow()
.as_ref() .as_ref()
.unwrap() .unwrap()
.args
.config_dir .config_dir
.clone() .clone()
.unwrap_or(format!( .unwrap_or(format!(
@@ -127,13 +176,19 @@ fn activate(app: &gtk::Application, args: Rc<RefCell<Option<Args>>>) {
); );
// Use the plugins in the config file, or the plugins specified with the override // Use the plugins in the config file, or the plugins specified with the override
let plugins = match &args.borrow().as_ref().unwrap().override_plugins { let plugins = match &runtime_data
Some(plugins) => plugins.iter().map(|path| PathBuf::from(path)).collect(), .borrow()
.as_ref()
.unwrap()
.args
.override_plugins
{
Some(plugins) => plugins.iter().map(PathBuf::from).collect(),
None => config.plugins, None => config.plugins,
}; };
// Make sure at least one plugin is specified // Make sure at least one plugin is specified
if plugins.len() == 0 { if plugins.is_empty() {
println!("At least one plugin needs to be enabled!"); println!("At least one plugin needs to be enabled!");
app.quit(); app.quit();
} }
@@ -199,10 +254,10 @@ fn activate(app: &gtk::Application, args: Rc<RefCell<Option<Args>>>) {
for plugin_view in plugins.iter() { for plugin_view in plugins.iter() {
let plugins_clone = plugins.clone(); let plugins_clone = plugins.clone();
plugin_view.list.connect_row_selected(move |list, row| { plugin_view.list.connect_row_selected(move |list, row| {
if let Some(_) = row { if row.is_some() {
let combined_matches = plugins_clone let combined_matches = plugins_clone
.iter() .iter()
.map(|view| { .flat_map(|view| {
view.list.children().into_iter().map(|child| { view.list.children().into_iter().map(|child| {
( (
child.dynamic_cast::<gtk::ListBoxRow>().unwrap(), child.dynamic_cast::<gtk::ListBoxRow>().unwrap(),
@@ -210,9 +265,9 @@ fn activate(app: &gtk::Application, args: Rc<RefCell<Option<Args>>>) {
) )
}) })
}) })
.flatten()
.collect::<Vec<(gtk::ListBoxRow, gtk::ListBox)>>(); .collect::<Vec<(gtk::ListBoxRow, gtk::ListBox)>>();
// Unselect everything except the new selection
for (_, _list) in combined_matches { for (_, _list) in combined_matches {
if _list != *list { if _list != *list {
_list.select_row(None::<&gtk::ListBoxRow>); _list.select_row(None::<&gtk::ListBoxRow>);
@@ -237,50 +292,61 @@ fn activate(app: &gtk::Application, args: Rc<RefCell<Option<Args>>>) {
// Handle other key presses for selection control and all other things that may be needed // Handle other key presses for selection control and all other things that may be needed
let entry_clone = entry.clone(); let entry_clone = entry.clone();
let plugins_clone = plugins.clone();
window.connect_key_press_event(move |window, event| { window.connect_key_press_event(move |window, event| {
use gdk::keys::constants; use gdk::keys::constants;
match event.keyval() { match event.keyval() {
// Close window on escape
constants::Escape => { constants::Escape => {
window.close(); window.close();
Inhibit(true) Inhibit(true)
} }
// Handle selections
constants::Down | constants::Tab | constants::Up => { constants::Down | constants::Tab | constants::Up => {
let combined_matches = plugins_clone // Combine all of the matches into a `Vec` to allow for easier handling of the selection
let combined_matches = plugins
.iter() .iter()
.map(|view| { .flat_map(|view| {
view.list.children().into_iter().map(|child| { view.list.children().into_iter().map(|child| {
( (
// All children of lists are GtkListBoxRow widgets
child.dynamic_cast::<gtk::ListBoxRow>().unwrap(), child.dynamic_cast::<gtk::ListBoxRow>().unwrap(),
view.list.clone(), view.list.clone(),
) )
}) })
}) })
.flatten()
.collect::<Vec<(gtk::ListBoxRow, gtk::ListBox)>>(); .collect::<Vec<(gtk::ListBoxRow, gtk::ListBox)>>();
let (selected_match, selected_list) = match plugins_clone // Get the selected match
let (selected_match, selected_list) = match plugins
.iter() .iter()
.find_map(|view| view.list.selected_row().map(|row| (row, view.list.clone()))) .find_map(|view| view.list.selected_row().map(|row| (row, view.list.clone())))
{ {
Some(selected) => selected, Some(selected) => selected,
None => { None => {
if event.keyval() != constants::Up { // If nothing is selected select either the top or bottom match based on the input
combined_matches[0] match event.keyval() {
constants::Down | constants::Tab => combined_matches[0]
.1 .1
.select_row(Some(&combined_matches[0].0)); .select_row(Some(&combined_matches[0].0)),
constants::Up => combined_matches[combined_matches.len() - 1]
.1
.select_row(Some(&combined_matches[combined_matches.len() - 1].0)),
_ => unreachable!(),
} }
return Inhibit(true); return Inhibit(true);
} }
}; };
// Clear the previous selection
selected_list.select_row(None::<&gtk::ListBoxRow>); selected_list.select_row(None::<&gtk::ListBoxRow>);
// Get the index of the current selection
let index = combined_matches let index = combined_matches
.iter() .iter()
.position(|(row, _)| *row == selected_match) .position(|(row, _)| *row == selected_match)
.unwrap(); .unwrap();
// Move the selection based on the input, loops from top to bottom and vice versa
match event.keyval() { match event.keyval() {
constants::Down | constants::Tab => { constants::Down | constants::Tab => {
if index < combined_matches.len() - 1 { if index < combined_matches.len() - 1 {
@@ -309,18 +375,19 @@ fn activate(app: &gtk::Application, args: Rc<RefCell<Option<Args>>>) {
Inhibit(true) Inhibit(true)
} }
// Handle when the selected match is "activated"
constants::Return => { constants::Return => {
let (selected_match, plugin) = match plugins_clone.iter().find_map(|view| { let (selected_match, plugin) = match plugins
view.list .iter()
.selected_row() .find_map(|view| view.list.selected_row().map(|row| (row, view.plugin)))
.map(|row| (row, view.plugin.clone())) {
}) {
Some(selected) => selected, Some(selected) => selected,
None => { None => {
return Inhibit(false); return Inhibit(false);
} }
}; };
// Perform actions based on the result of handling the selection
match plugin.handle_selection()(unsafe { match plugin.handle_selection()(unsafe {
(*selected_match.data::<Match>("match").unwrap().as_ptr()).clone() (*selected_match.data::<Match>("match").unwrap().as_ptr()).clone()
}) { }) {
@@ -329,16 +396,25 @@ fn activate(app: &gtk::Application, args: Rc<RefCell<Option<Args>>>) {
Inhibit(true) Inhibit(true)
} }
HandleResult::Refresh => { HandleResult::Refresh => {
refresh_matches(entry_clone.text().to_string(), plugins_clone.clone()); refresh_matches(entry_clone.text().to_string(), plugins.clone());
Inhibit(false) Inhibit(false)
} }
HandleResult::Copy(bytes) => {
runtime_data.borrow_mut().as_mut().unwrap().post_run_action =
PostRunAction::Copy(bytes.into());
window.close();
Inhibit(true)
}
} }
} }
_ => Inhibit(false), _ => Inhibit(false),
} }
}); });
let main_vbox = gtk::Box::new(gtk::Orientation::Vertical, 10); let main_vbox = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.name(style_names::MAIN)
.build();
main_vbox.add(&entry); main_vbox.add(&entry);
window.add(&main_vbox); window.add(&main_vbox);
window.show_all(); window.show_all();
@@ -348,11 +424,13 @@ fn activate(app: &gtk::Application, args: Rc<RefCell<Option<Args>>>) {
} }
fn handle_matches(matches: RVec<Match>, plugin_view: PluginView) { fn handle_matches(matches: RVec<Match>, plugin_view: PluginView) {
// Clear out the old matches from the list
for widget in plugin_view.list.children() { for widget in plugin_view.list.children() {
plugin_view.list.remove(&widget); plugin_view.list.remove(&widget);
} }
if matches.len() == 0 { // If there are no matches, hide the plugin's results
if matches.is_empty() {
plugin_view.row.hide(); plugin_view.row.hide();
return; return;
} }
@@ -364,17 +442,22 @@ fn handle_matches(matches: RVec<Match>, plugin_view: PluginView) {
.name(style_names::MATCH) .name(style_names::MATCH)
.hexpand(true) .hexpand(true)
.build(); .build();
hbox.add( if let ROption::RSome(icon) = &_match.icon {
&gtk::Image::builder() hbox.add(
.icon_name(&_match.icon) &gtk::Image::builder()
.name(style_names::MATCH) .icon_name(icon)
.pixel_size(32) .name(style_names::MATCH)
.build(), .pixel_size(32)
); .build(),
);
}
let title = gtk::Label::builder() let title = gtk::Label::builder()
.name(style_names::MATCH_TITLE) .name(style_names::MATCH_TITLE)
.wrap(true)
.use_markup(true) // Allow pango markup
.halign(gtk::Align::Start) .halign(gtk::Align::Start)
.valign(gtk::Align::Center) .valign(gtk::Align::Center)
.vexpand(true)
.label(&_match.title) .label(&_match.title)
.build(); .build();
@@ -391,6 +474,8 @@ fn handle_matches(matches: RVec<Match>, plugin_view: PluginView) {
title_desc_box.add( title_desc_box.add(
&gtk::Label::builder() &gtk::Label::builder()
.name(style_names::MATCH_DESC) .name(style_names::MATCH_DESC)
.wrap(true)
.use_markup(true) // Allow pango markup
.halign(gtk::Align::Start) .halign(gtk::Align::Start)
.valign(gtk::Align::Center) .valign(gtk::Align::Center)
.label(desc) .label(desc)
@@ -402,7 +487,10 @@ fn handle_matches(matches: RVec<Match>, plugin_view: PluginView) {
hbox.add(&title); hbox.add(&title);
} }
} }
let row = gtk::ListBoxRow::builder().name(style_names::MATCH).build(); let row = gtk::ListBoxRow::builder()
.name(style_names::MATCH)
.height_request(32)
.build();
row.add(&hbox); row.add(&hbox);
// GTK data setting is not type checked, so it is unsafe. // GTK data setting is not type checked, so it is unsafe.
// Only `Match` objects are stored though. // Only `Match` objects are stored though.
@@ -416,11 +504,13 @@ fn handle_matches(matches: RVec<Match>, plugin_view: PluginView) {
plugin_view.row.show_all(); plugin_view.row.show_all();
} }
/// Create the info box for the plugin
fn create_info_box(info: &PluginInfo) -> gtk::Box { fn create_info_box(info: &PluginInfo) -> gtk::Box {
let info_box = gtk::Box::builder() let info_box = gtk::Box::builder()
.orientation(gtk::Orientation::Horizontal) .orientation(gtk::Orientation::Horizontal)
.name(style_names::PLUGIN) .name(style_names::PLUGIN)
.width_request(200) .width_request(200)
.height_request(32)
.expand(false) .expand(false)
.spacing(10) .spacing(10)
.build(); .build();
@@ -428,7 +518,7 @@ fn create_info_box(info: &PluginInfo) -> gtk::Box {
&gtk::Image::builder() &gtk::Image::builder()
.icon_name(&info.icon) .icon_name(&info.icon)
.name(style_names::PLUGIN) .name(style_names::PLUGIN)
.pixel_size(48) .pixel_size(32)
.halign(gtk::Align::Start) .halign(gtk::Align::Start)
.valign(gtk::Align::Start) .valign(gtk::Align::Start)
.build(), .build(),
@@ -438,11 +528,23 @@ fn create_info_box(info: &PluginInfo) -> gtk::Box {
.label(&info.name) .label(&info.name)
.name(style_names::PLUGIN) .name(style_names::PLUGIN)
.halign(gtk::Align::End) .halign(gtk::Align::End)
.valign(gtk::Align::Start) .valign(gtk::Align::Center)
.hexpand(true) .hexpand(true)
.build(), .build(),
); );
info_box // This is so that we can align the plugin name with the icon. GTK would not let it be properly aligned otherwise.
let main_box = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.name(style_names::PLUGIN)
.build();
main_box.add(&info_box);
main_box.add(
&gtk::Box::builder()
.orientation(gtk::Orientation::Horizontal)
.name(style_names::PLUGIN)
.build(),
);
main_box
} }
/// Refresh the matches from the plugins /// Refresh the matches from the plugins
@@ -450,9 +552,14 @@ fn refresh_matches(input: String, plugins: Rc<Vec<PluginView>>) {
for plugin_view in plugins.iter() { for plugin_view in plugins.iter() {
let id = plugin_view.plugin.get_matches()(input.clone().into()); let id = plugin_view.plugin.get_matches()(input.clone().into());
let plugin_view = plugin_view.clone(); let plugin_view = plugin_view.clone();
glib::timeout_add_local(Duration::from_micros(1000), move || { // If the input is empty, skip getting matches and just clear everything out.
async_match(plugin_view.clone(), id) if input.is_empty() {
}); handle_matches(RVec::new(), plugin_view);
} else {
glib::timeout_add_local(Duration::from_micros(1000), move || {
async_match(plugin_view.clone(), id)
});
}
} }
} }

View File

@@ -12,3 +12,4 @@ crate-type = ["cdylib"]
anyrun-plugin = { path = "../../anyrun-plugin" } anyrun-plugin = { path = "../../anyrun-plugin" }
abi_stable = "0.11.1" abi_stable = "0.11.1"
sublime_fuzzy = "0.7.0" sublime_fuzzy = "0.7.0"
fuzzy-matcher = "0.3.7"

View File

@@ -1,18 +1,16 @@
use abi_stable::std_types::{ROption, RString, RVec}; use abi_stable::std_types::{ROption, RString, RVec};
use scrubber::DesktopEntry;
use std::{process::Command, sync::RwLock, thread};
use anyrun_plugin::{anyrun_interface::HandleResult, *}; use anyrun_plugin::{anyrun_interface::HandleResult, *};
use fuzzy_matcher::FuzzyMatcher;
use scrubber::DesktopEntry;
use std::process::Command;
mod scrubber; mod scrubber;
static ENTRIES: RwLock<Vec<(DesktopEntry, u64)>> = RwLock::new(Vec::new()); pub fn handler(selection: Match, entries: &mut Vec<(DesktopEntry, u64)>) -> HandleResult {
pub fn handler(selection: Match) -> HandleResult {
let entries = ENTRIES.read().unwrap();
let entry = entries let entry = entries
.iter() .iter()
.find_map(|(entry, id)| { .find_map(|(entry, id)| {
if *id == selection.id { if *id == selection.id.unwrap() {
Some(entry) Some(entry)
} else { } else {
None None
@@ -27,46 +25,32 @@ pub fn handler(selection: Match) -> HandleResult {
HandleResult::Close HandleResult::Close
} }
pub fn init(_config_dir: RString) { pub fn init(_config_dir: RString) -> Vec<(DesktopEntry, u64)> {
thread::spawn(|| { scrubber::scrubber().expect("Failed to load desktop entries!")
*ENTRIES.write().unwrap() = match scrubber::scrubber() {
Ok(results) => results,
Err(why) => {
println!("Error reading desktop entries: {}", why);
return;
}
};
});
} }
pub fn get_matches(input: RString) -> RVec<Match> { pub fn get_matches(input: RString, entries: &mut Vec<(DesktopEntry, u64)>) -> RVec<Match> {
if input.len() == 0 { let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case();
return RVec::new(); let mut entries = entries
}
let mut entries = ENTRIES
.read()
.unwrap()
.clone() .clone()
.into_iter() .into_iter()
.filter_map(|(entry, id)| { .filter_map(|(entry, id)| {
match sublime_fuzzy::best_match(&input.to_lowercase(), &entry.name.to_lowercase()) { matcher
Some(val) => Some((entry, id, val.score())), .fuzzy_match(&entry.name, &input)
None => None, .map(|val| (entry, id, val))
}
}) })
.collect::<Vec<(DesktopEntry, u64, isize)>>(); .collect::<Vec<_>>();
entries.sort_by(|a, b| b.1.cmp(&a.1)); entries.sort_by(|a, b| b.2.cmp(&a.2));
entries.truncate(5); entries.truncate(5);
entries entries
.into_iter() .into_iter()
.map(|(entry, id, _)| Match { .map(|(entry, id, _)| Match {
title: entry.name.into(), title: entry.name.into(),
icon: entry.icon.into(), icon: ROption::RSome(entry.icon.into()),
description: ROption::RNone, description: ROption::RNone,
id, id: ROption::RSome(id),
}) })
.collect() .collect()
} }
@@ -78,4 +62,4 @@ pub fn info() -> PluginInfo {
} }
} }
plugin!(init, info, get_matches, handler); plugin!(init, info, get_matches, handler, Vec<(DesktopEntry, u64)>);

View File

@@ -115,7 +115,7 @@ pub fn scrubber() -> Result<Vec<(DesktopEntry, u64)>, Box<dyn std::error::Error>
Ok(entry) => entry, Ok(entry) => entry,
Err(_why) => return None, Err(_why) => return None,
}; };
DesktopEntry::from_dir_entry(&entry).map(|val| (val, id)) DesktopEntry::from_dir_entry(entry).map(|val| (val, id))
}) })
.collect()) .collect())
} }

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "web-search" name = "rink"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
@@ -11,3 +11,4 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
anyrun-plugin = { path = "../../anyrun-plugin" } anyrun-plugin = { path = "../../anyrun-plugin" }
abi_stable = "0.11.1" abi_stable = "0.11.1"
rink-core = "0.6"

31
plugins/rink/src/lib.rs Normal file
View File

@@ -0,0 +1,31 @@
use abi_stable::std_types::{ROption, RString, RVec};
use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo};
fn init(_config_dir: RString) {}
fn info() -> PluginInfo {
PluginInfo {
name: "Rink".into(),
icon: "accessories-calculator".into(),
}
}
fn get_matches(input: RString, _: &mut ()) -> RVec<Match> {
let mut ctx = rink_core::simple_context().unwrap();
match rink_core::one_line(&mut ctx, &input) {
Ok(result) => vec![Match {
title: result.into(),
icon: ROption::RNone,
description: ROption::RNone,
id: ROption::RNone,
}]
.into(),
Err(_) => RVec::new(),
}
}
fn handler(selection: Match, _: &mut ()) -> HandleResult {
HandleResult::Copy(selection.title.into_bytes())
}
plugin!(init, info, get_matches, handler, ());

View File

@@ -11,3 +11,6 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
anyrun-plugin = { path = "../../anyrun-plugin" } anyrun-plugin = { path = "../../anyrun-plugin" }
abi_stable = "0.11.1" abi_stable = "0.11.1"
ron = "0.8.0"
serde = { version = "1.0.152", features = ["derive"] }
fuzzy-matcher = "0.3.7"

28
plugins/symbols/build.rs Normal file
View File

@@ -0,0 +1,28 @@
use std::{
env,
fs::{self, File},
io::Write,
};
fn main() {
let string = fs::read_to_string("res/UnicodeData.txt").expect("Failed to load unicode data!");
let mut file = File::create(format!("{}/unicode.rs", env::var("OUT_DIR").unwrap()))
.expect("Unable to create unicode output file!");
file.write_all(b"#[allow(text_direction_codepoint_in_literal)]\nconst UNICODE_CHARS: &[(&str, &str)] = &[\n")
.unwrap();
string.lines().for_each(|line| {
let fields = line.split(';').collect::<Vec<_>>();
let chr = match char::from_u32(u32::from_str_radix(fields[0], 16).unwrap()) {
Some(char) => char,
None => return,
};
if fields[1] != "<control>" {
file.write_all(format!("(r#\"{}\"#, r#\"{}\"#),\n", fields[1], chr).as_bytes())
.unwrap();
}
});
file.write_all(b"];\n").unwrap();
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,88 @@
use std::{collections::HashMap, fs};
use abi_stable::std_types::{ROption, RString, RVec}; use abi_stable::std_types::{ROption, RString, RVec};
use anyrun_plugin::{plugin, anyrun_interface::HandleResult, Match, PluginInfo}; use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo};
use fuzzy_matcher::FuzzyMatcher;
use serde::Deserialize;
pub fn init(_config_dir: RString) {} include!(concat!(env!("OUT_DIR"), "/unicode.rs"));
pub fn info() -> PluginInfo { #[derive(Clone, Debug)]
struct Symbol {
chr: String,
name: String,
}
#[derive(Deserialize, Debug)]
struct Config {
symbols: HashMap<String, String>,
}
fn init(config_dir: RString) -> Vec<Symbol> {
// Try to load the config file, if it does not exist only use the static unicode characters
if let Ok(content) = fs::read_to_string(format!("{}/symbols.ron", config_dir)) {
match ron::from_str::<Config>(&content) {
Ok(config) => {
let symbols = UNICODE_CHARS
.iter()
.map(|(name, chr)| (name.to_string(), chr.to_string()))
.chain(config.symbols.into_iter())
.map(|(name, chr)| Symbol { chr, name })
.collect();
return symbols;
}
Err(why) => {
println!("Error parsing symbols config file: {}", why);
}
}
}
UNICODE_CHARS
.iter()
.map(|(name, chr)| Symbol {
chr: chr.to_string(),
name: name.to_string(),
})
.collect()
}
fn info() -> PluginInfo {
PluginInfo { PluginInfo {
name: "Symbols".into(), name: "Symbols".into(),
icon: "emblem-mail".into(), icon: "accessories-character-map".into(),
} }
} }
pub fn get_matches(input: RString) -> RVec<Match> { fn get_matches(input: RString, symbols: &mut Vec<Symbol>) -> RVec<Match> {
vec![Match { let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().ignore_case();
title: "Test".into(), let mut symbols = symbols
description: ROption::RNone, .clone()
icon: "dialog-warning".into(), .into_iter()
id: 0, .filter_map(|symbol| {
}] matcher
.into() .fuzzy_match(&symbol.name, &input)
.map(|score| (symbol, score))
})
.collect::<Vec<_>>();
// Sort the symbol list according to the score
symbols.sort_by(|a, b| b.1.cmp(&a.1));
symbols.truncate(3);
symbols
.into_iter()
.map(|(symbol, _)| Match {
title: symbol.chr.into(),
description: ROption::RSome(symbol.name.into()),
icon: ROption::RNone,
id: ROption::RNone,
})
.collect()
} }
pub fn handler(selection: Match) -> HandleResult { fn handler(selection: Match, _symbols: &mut Vec<Symbol>) -> HandleResult {
HandleResult::Close HandleResult::Copy(selection.title.into_bytes())
} }
plugin!(init, info, get_matches, handler); plugin!(init, info, get_matches, handler, Vec<Symbol>);

View File

@@ -1,35 +0,0 @@
use abi_stable::std_types::{ROption, RString, RVec};
use anyrun_plugin::{plugin, anyrun_interface::HandleResult, Match, PluginInfo};
pub fn init(_config_dir: RString) {}
pub fn info() -> PluginInfo {
PluginInfo {
name: "Web search".into(),
icon: "system-search".into(),
}
}
pub fn get_matches(input: RString) -> RVec<Match> {
vec![
Match {
title: "DDG it!".into(),
description: ROption::RSome(format!(r#"Look up "{}" with DuckDuckGo"#, input).into()),
icon: "emblem-web".into(),
id: 0,
},
Match {
title: "Startpage it!".into(),
description: ROption::RSome(format!(r#"Look up "{}" with Startpage"#, input).into()),
icon: "emblem-web".into(),
id: 0,
},
]
.into()
}
pub fn handler(selection: Match) -> HandleResult {
HandleResult::Close
}
plugin!(init, info, get_matches, handler);