Merge pull request #949 from federico-terzi/dev

v2.1.3-alpha
This commit is contained in:
Federico Terzi 2022-01-17 20:49:10 +01:00 committed by GitHub
commit 22987c6518
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 226 additions and 24 deletions

24
.github/scripts/ubuntu/build_deb.sh vendored Executable file
View File

@ -0,0 +1,24 @@
#!/bin/bash
set -e
echo "Installing cargo-deb"
cargo install cargo-deb --version 1.34.0
cd espanso
echo "Building X11 deb package"
cargo deb -p espanso
echo "Building Wayland deb package"
cargo deb -p espanso --variant wayland -- --features wayland
cd ..
cp espanso/target/debian/espanso_*.deb espanso-debian-x11-amd64.deb
sha256sum espanso-debian-x11-amd64.deb > espanso-debian-x11-amd64-sha256.txt
cp espanso/target/debian/espanso-wayland*.deb espanso-debian-wayland-amd64.deb
sha256sum espanso-debian-wayland-amd64.deb > espanso-debian-wayland-amd64-sha256.txt
ls -la
echo "Copying to mounted volume"
cp espanso-debian-* /shared

View File

@ -117,6 +117,34 @@ jobs:
if: ${{ github.ref == 'refs/heads/master' }} if: ${{ github.ref == 'refs/heads/master' }}
run: | run: |
gh release upload ${{ needs.extract-version.outputs.espanso_version }} Espanso-X11.AppImage Espanso-X11.AppImage.sha256.txt gh release upload ${{ needs.extract-version.outputs.espanso_version }} Espanso-X11.AppImage Espanso-X11.AppImage.sha256.txt
linux-deb:
needs: ["extract-version", "create-release"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Print target version
run: |
echo Using version ${{ needs.extract-version.outputs.espanso_version }}
- name: Build docker image
run: |
sudo docker build -t espanso-ubuntu . -f .github/scripts/ubuntu/Dockerfile
- name: Build Deb packages
run: |
sudo docker run --rm -v "$(pwd):/shared" espanso-ubuntu espanso/.github/scripts/ubuntu/build_deb.sh
- uses: actions/upload-artifact@v2
name: "Upload artifacts"
with:
name: Ubuntu-Debian Artifacts
path: |
espanso-debian-x11-amd64.deb
espanso-debian-wayland-amd64.deb
- name: Upload artifacts to Github Releases (if master)
if: ${{ github.ref == 'refs/heads/master' }}
run: |
gh release upload ${{ needs.extract-version.outputs.espanso_version }} espanso-debian-x11-amd64.deb espanso-debian-wayland-amd64.deb espanso-debian-x11-amd64-sha256.txt espanso-debian-wayland-amd64-sha256.txt
macos-intel: macos-intel:
needs: ["extract-version", "create-release"] needs: ["extract-version", "create-release"]
@ -203,4 +231,26 @@ jobs:
- name: Upload artifacts to Github Releases (if master) - name: Upload artifacts to Github Releases (if master)
if: ${{ github.ref == 'refs/heads/master' }} if: ${{ github.ref == 'refs/heads/master' }}
run: | run: |
gh release upload ${{ needs.extract-version.outputs.espanso_version }} Espanso-Mac-M1.zip Espanso-Mac-M1.zip.sha256.txt gh release upload ${{ needs.extract-version.outputs.espanso_version }} Espanso-Mac-M1.zip Espanso-Mac-M1.zip.sha256.txt
macos-publish-homebrew:
needs: ["extract-version", "create-release", "macos-m1", "macos-intel"]
runs-on: macos-11
steps:
- uses: actions/checkout@v2
- name: Print target version
run: |
echo Using version ${{ needs.extract-version.outputs.espanso_version }}
- name: "Setup SSH deploy key"
uses: webfactory/ssh-agent@fc49353b67b2b7c1e0e6a600572d01a69f2672dd
with:
ssh-private-key: ${{ secrets.HOMEBREW_CASK_SSH_PRIVATE_KEY }}
- name: Create and Publish Homebrew Cask
if: ${{ github.ref == 'refs/heads/master' }}
run: |
VERSION="${{ needs.extract-version.outputs.espanso_version }}" ./scripts/publish_homebrew_version.sh
echo "Cask formula has been published here: "

2
Cargo.lock generated
View File

@ -572,7 +572,7 @@ dependencies = [
[[package]] [[package]]
name = "espanso" name = "espanso"
version = "2.1.2-alpha" version = "2.1.3-alpha"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"caps", "caps",

View File

@ -271,7 +271,7 @@ impl Config for ResolvedConfig {
match self.parsed.search_trigger.as_deref() { match self.parsed.search_trigger.as_deref() {
Some("OFF") | Some("off") => None, Some("OFF") | Some("off") => None,
Some(x) => Some(x.to_string()), Some(x) => Some(x.to_string()),
None => Some("jkj".to_string()), None => None,
} }
} }

View File

@ -300,6 +300,7 @@ pub fn try_convert_into_match(
effect, effect,
label: yaml_match.label, label: yaml_match.label,
id: next_id(), id: next_id(),
search_terms: yaml_match.search_terms.unwrap_or_default(),
}, },
warnings, warnings,
)) ))

View File

@ -114,6 +114,9 @@ pub struct YAMLMatch {
#[serde(default)] #[serde(default)]
pub html: Option<String>, pub html: Option<String>,
#[serde(default)]
pub search_terms: Option<Vec<String>>,
} }
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]

View File

@ -35,6 +35,7 @@ pub struct Match {
// Metadata // Metadata
pub label: Option<String>, pub label: Option<String>,
pub search_terms: Vec<String>,
} }
impl Default for Match { impl Default for Match {
@ -44,6 +45,7 @@ impl Default for Match {
effect: MatchEffect::None, effect: MatchEffect::None,
label: None, label: None,
id: 0, id: 0,
search_terms: vec![],
} }
} }
} }
@ -66,6 +68,15 @@ impl Match {
pub fn cause_description(&self) -> Option<&str> { pub fn cause_description(&self) -> Option<&str> {
self.cause.description() self.cause.description()
} }
pub fn search_terms(&self) -> Vec<&str> {
self
.search_terms
.iter()
.map(|term| term.as_str())
.chain(self.cause.search_terms())
.collect()
}
} }
// Causes // Causes
@ -100,6 +111,14 @@ impl MatchCause {
// TODO: insert rendering for hotkey/shortcut // TODO: insert rendering for hotkey/shortcut
// TODO: insert rendering for regex? I'm worried it might be too long // TODO: insert rendering for regex? I'm worried it might be too long
} }
pub fn search_terms(&self) -> Vec<&str> {
if let MatchCause::Trigger(trigger_cause) = &self {
trigger_cause.triggers.iter().map(|s| s.as_str()).collect()
} else {
vec![]
}
}
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]

View File

@ -99,7 +99,7 @@ impl Middleware for ContextMenuMiddleware {
0, 0,
MenuItem::Simple(SimpleMenuItem { MenuItem::Simple(SimpleMenuItem {
id: CONTEXT_ITEM_SECURE_INPUT_EXPLAIN, id: CONTEXT_ITEM_SECURE_INPUT_EXPLAIN,
label: "Why is espanso not working?".to_string(), label: "Why is Espanso not working?".to_string(),
}), }),
); );
items.insert( items.insert(

View File

@ -32,7 +32,7 @@ use crate::{keys, InjectionOptions, Injector};
#[allow(improper_ctypes)] #[allow(improper_ctypes)]
#[link(name = "espansoinject", kind = "static")] #[link(name = "espansoinject", kind = "static")]
extern "C" { extern "C" {
pub fn inject_string(string: *const c_char); pub fn inject_string(string: *const c_char, delay: i32);
pub fn inject_separate_vkeys(vkey_array: *const i32, vkey_count: i32, delay: i32); pub fn inject_separate_vkeys(vkey_array: *const i32, vkey_count: i32, delay: i32);
pub fn inject_vkeys_combination(vkey_array: *const i32, vkey_count: i32, delay: i32); pub fn inject_vkeys_combination(vkey_array: *const i32, vkey_count: i32, delay: i32);
} }
@ -60,10 +60,10 @@ impl MacInjector {
} }
impl Injector for MacInjector { impl Injector for MacInjector {
fn send_string(&self, string: &str, _: InjectionOptions) -> Result<()> { fn send_string(&self, string: &str, options: InjectionOptions) -> Result<()> {
let c_string = CString::new(string)?; let c_string = CString::new(string)?;
unsafe { unsafe {
inject_string(c_string.as_ptr()); inject_string(c_string.as_ptr(), options.delay);
} }
Ok(()) Ok(())
} }

View File

@ -23,7 +23,7 @@
#include <stdint.h> #include <stdint.h>
// Inject a complete string using the KEYEVENTF_UNICODE flag // Inject a complete string using the KEYEVENTF_UNICODE flag
extern "C" void inject_string(char * string); extern "C" void inject_string(char * string, int32_t delay);
// Send a sequence of vkey presses and releases // Send a sequence of vkey presses and releases
extern "C" void inject_separate_vkeys(int32_t *vkey_array, int32_t vkey_count, int32_t delay); extern "C" void inject_separate_vkeys(int32_t *vkey_array, int32_t vkey_count, int32_t delay);

View File

@ -27,8 +27,10 @@
// so that we can later skip them in the detect module. // so that we can later skip them in the detect module.
CGPoint ESPANSO_POINT_MARKER = CGPointMake(-27469, 0); CGPoint ESPANSO_POINT_MARKER = CGPointMake(-27469, 0);
void inject_string(char *string) void inject_string(char *string, int32_t delay)
{ {
long udelay = delay * 1000;
char * stringCopy = strdup(string); char * stringCopy = strdup(string);
dispatch_async(dispatch_get_main_queue(), ^(void) { dispatch_async(dispatch_get_main_queue(), ^(void) {
// Convert the c string to a UniChar array as required by the CGEventKeyboardSetUnicodeString method // Convert the c string to a UniChar array as required by the CGEventKeyboardSetUnicodeString method
@ -49,7 +51,7 @@ void inject_string(char *string)
CGEventPost(kCGHIDEventTap, e2); CGEventPost(kCGHIDEventTap, e2);
CFRelease(e2); CFRelease(e2);
usleep(2000); usleep(udelay);
} }
// Because of a bug ( or undocumented limit ) of the CGEventKeyboardSetUnicodeString method // Because of a bug ( or undocumented limit ) of the CGEventKeyboardSetUnicodeString method
@ -69,7 +71,7 @@ void inject_string(char *string)
CGEventPost(kCGHIDEventTap, e); CGEventPost(kCGHIDEventTap, e);
CFRelease(e); CFRelease(e);
usleep(2000); usleep(udelay);
// Some applications require an explicit release of the space key // Some applications require an explicit release of the space key
// For more information: https://github.com/federico-terzi/espanso/issues/159 // For more information: https://github.com/federico-terzi/espanso/issues/159
@ -78,7 +80,7 @@ void inject_string(char *string)
CGEventPost(kCGHIDEventTap, e2); CGEventPost(kCGHIDEventTap, e2);
CFRelease(e2); CFRelease(e2);
usleep(2000); usleep(udelay);
i += chunk_size; i += chunk_size;
} }

View File

@ -44,7 +44,9 @@ fn exact_match(query: &str, items: &[SearchItem]) -> Vec<usize> {
.iter() .iter()
.enumerate() .enumerate()
.filter(|(_, item)| { .filter(|(_, item)| {
item.label.contains(query) || item.trigger.as_deref().map_or(false, |t| t.contains(query)) item.label.contains(query)
|| item.trigger.as_deref().map_or(false, |t| t.contains(query))
|| item.search_terms.iter().any(|term| term.contains(query))
}) })
.map(|(i, _)| i) .map(|(i, _)| i)
.collect() .collect()
@ -61,6 +63,10 @@ fn case_insensitive_exact_match(query: &str, items: &[SearchItem]) -> Vec<usize>
.trigger .trigger
.as_deref() .as_deref()
.map_or(false, |t| t.to_lowercase().contains(query)) .map_or(false, |t| t.to_lowercase().contains(query))
|| item
.search_terms
.iter()
.any(|term| term.to_lowercase().contains(&lowercase_query))
}) })
.map(|(i, _)| i) .map(|(i, _)| i)
.collect() .collect()
@ -79,6 +85,10 @@ fn case_insensitive_keyword(query: &str, items: &[SearchItem]) -> Vec<usize> {
.trigger .trigger
.as_deref() .as_deref()
.map_or(false, |t| t.to_lowercase().contains(keyword)) .map_or(false, |t| t.to_lowercase().contains(keyword))
&& !item
.search_terms
.iter()
.any(|term| term.to_lowercase().contains(keyword))
{ {
return false; return false;
} }

View File

@ -58,6 +58,7 @@ pub struct SearchItem {
pub id: String, pub id: String,
pub label: String, pub label: String,
pub trigger: Option<String>, pub trigger: Option<String>,
pub search_terms: Vec<String>,
#[serde(default)] #[serde(default)]
pub is_builtin: bool, pub is_builtin: bool,

View File

@ -28,6 +28,7 @@ pub fn generate(config: SearchConfig) -> types::Search {
id: item.id, id: item.id,
label: item.label, label: item.label,
trigger: item.trigger, trigger: item.trigger,
search_terms: item.search_terms,
is_builtin: item.is_builtin, is_builtin: item.is_builtin,
}) })
.collect(); .collect();

View File

@ -26,6 +26,7 @@ pub mod types {
pub id: String, pub id: String,
pub label: String, pub label: String,
pub trigger: Option<String>, pub trigger: Option<String>,
pub search_terms: Vec<String>,
pub is_builtin: bool, pub is_builtin: bool,
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "espanso" name = "espanso"
version = "2.1.2-alpha" version = "2.1.3-alpha"
authors = ["Federico Terzi <federicoterzi96@gmail.com>"] authors = ["Federico Terzi <federicoterzi96@gmail.com>"]
license = "GPL-3.0" license = "GPL-3.0"
description = "Cross-platform Text Expander written in Rust" description = "Cross-platform Text Expander written in Rust"
@ -72,4 +72,16 @@ espanso-mac-utils = { path = "../espanso-mac-utils" }
[target.'cfg(target_os="linux")'.dependencies] [target.'cfg(target_os="linux")'.dependencies]
caps = "0.5.2" caps = "0.5.2"
const_format = "0.2.14" const_format = "0.2.14"
regex = "1.4.3" regex = "1.4.3"
[package.metadata.deb]
maintainer = "Federico Terzi <federicoterzi96@gmail.com>"
depends = "$auto, systemd, libxtst6, xclip, libnotify-bin, libxkbcommon0, libwxgtk3.0-gtk3-0v5"
section = "utility"
license-file = ["../LICENSE", "1"]
[package.metadata.deb.variants.wayland]
depends = "$auto, systemd, libnotify-bin, libxkbcommon0, libwxgtk3.0-gtk3-0v5"
# TODO: once this issue [1] is fixed, we should create a variant for
# wayland to automatically run the setcap script.
# [1]: https://github.com/mmstick/cargo-deb/issues/151

View File

@ -103,6 +103,8 @@ fn service_main(args: CliModuleArgs) -> i32 {
stop_main(&paths); stop_main(&paths);
std::thread::sleep(std::time::Duration::from_millis(300)); std::thread::sleep(std::time::Duration::from_millis(300));
return start_main(&paths, &paths_overrides, sub_args); return start_main(&paths, &paths_overrides, sub_args);
} else {
eprintln!("Invalid usage, please run `espanso service --help` for more information.");
} }
SERVICE_SUCCESS SERVICE_SUCCESS

View File

@ -33,9 +33,7 @@ impl SecureInputManagerAdapter {
impl SecureInputManager for SecureInputManagerAdapter { impl SecureInputManager for SecureInputManagerAdapter {
fn display_secure_input_troubleshoot(&self) -> anyhow::Result<()> { fn display_secure_input_troubleshoot(&self) -> anyhow::Result<()> {
// TODO: replace with actual URL opener::open_browser("https://espanso.org/docs/next/troubleshooting/secure-input/")?;
// TODO: in the future, this might be a self-contained WebView window
opener::open_browser("https://espanso.org/docs")?;
Ok(()) Ok(())
} }

View File

@ -32,6 +32,7 @@ pub struct MatchSummary<'a> {
pub id: i32, pub id: i32,
pub label: &'a str, pub label: &'a str,
pub tag: Option<&'a str>, pub tag: Option<&'a str>,
pub additional_search_terms: Vec<&'a str>,
pub is_builtin: bool, pub is_builtin: bool,
} }
@ -65,6 +66,11 @@ impl<'a> MatchSelector for MatchSelectorAdapter<'a> {
id: m.id.to_string(), id: m.id.to_string(),
label: clipped_label, label: clipped_label,
tag: m.tag.map(String::from), tag: m.tag.map(String::from),
additional_search_terms: m
.additional_search_terms
.into_iter()
.map(String::from)
.collect(),
is_builtin: m.is_builtin, is_builtin: m.is_builtin,
} }
}) })

View File

@ -49,6 +49,7 @@ fn convert_items(choices: &[espanso_render::extension::choice::Choice]) -> Vec<S
id: choice.id.to_string(), id: choice.id.to_string(),
label: choice.label.to_string(), label: choice.label.to_string(),
tag: None, tag: None,
additional_search_terms: vec![],
is_builtin: false, is_builtin: false,
}) })
.collect() .collect()

View File

@ -129,12 +129,14 @@ impl<'a> super::engine::process::middleware::match_select::MatchProvider<'a>
id: m.id, id: m.id,
label: m.description(), label: m.description(),
tag: m.cause_description(), tag: m.cause_description(),
additional_search_terms: m.search_terms(),
is_builtin: false, is_builtin: false,
}, },
MatchVariant::Builtin(m) => MatchSummary { MatchVariant::Builtin(m) => MatchSummary {
id: m.id, id: m.id,
label: m.label, label: m.label,
tag: m.triggers.first().map(String::as_ref), tag: m.triggers.first().map(String::as_ref),
additional_search_terms: vec![],
is_builtin: true, is_builtin: true,
}, },
}) })

View File

@ -32,6 +32,7 @@ pub struct SearchItem {
pub id: String, pub id: String,
pub label: String, pub label: String,
pub tag: Option<String>, pub tag: Option<String>,
pub additional_search_terms: Vec<String>,
pub is_builtin: bool, pub is_builtin: bool,
} }

View File

@ -73,6 +73,7 @@ struct ModuloSearchItemConfig<'a> {
id: &'a str, id: &'a str,
label: &'a str, label: &'a str,
trigger: Option<&'a str>, trigger: Option<&'a str>,
search_terms: Vec<&'a str>,
is_builtin: bool, is_builtin: bool,
} }
@ -84,6 +85,15 @@ fn convert_items(items: &[SearchItem]) -> Vec<ModuloSearchItemConfig> {
id: &item.id, id: &item.id,
label: &item.label, label: &item.label,
trigger: item.tag.as_deref(), trigger: item.tag.as_deref(),
search_terms: if item.additional_search_terms.is_empty() {
vec![]
} else {
item
.additional_search_terms
.iter()
.map(|term| term.as_str())
.collect()
},
is_builtin: item.is_builtin, is_builtin: item.is_builtin,
}) })
.collect() .collect()

View File

@ -360,7 +360,7 @@ For example, specifying 'email' is equivalent to 'match/email.yml'."#))
.subcommand(restart_subcommand.clone()) .subcommand(restart_subcommand.clone())
.subcommand(stop_subcommand.clone()) .subcommand(stop_subcommand.clone())
.subcommand(status_subcommand.clone()) .subcommand(status_subcommand.clone())
.about("Register and manage 'espanso' as a system service."), .about("A collection of commands to manage the Espanso service (for example, enabling auto-start on system boot)."),
) )
.subcommand(start_subcommand) .subcommand(start_subcommand)
.subcommand(restart_subcommand) .subcommand(restart_subcommand)

View File

@ -19,8 +19,6 @@
use std::sync::Arc; use std::sync::Arc;
use espanso_config::config::Backend;
use crate::patch::patches::{PatchedConfig, Patches}; use crate::patch::patches::{PatchedConfig, Patches};
use crate::patch::PatchDefinition; use crate::patch::PatchDefinition;
@ -34,8 +32,6 @@ pub fn patch() -> PatchDefinition {
base, base,
name, name,
Patches { Patches {
paste_shortcut: Some(Some("CTRL+SHIFT+V".to_string())),
backend: Some(Backend::Clipboard),
key_delay: Some(Some(15)), key_delay: Some(Some(15)),
inject_delay: Some(Some(15)), inject_delay: Some(Some(15)),
..Default::default() ..Default::default()

View File

@ -0,0 +1,43 @@
#!/bin/bash
set -e
if [[ -z "$VERSION" ]]; then
echo "Missing target VERSION environment variable, please specify it"
exit 1
fi
# Removing the v suffix, if present
VERSION=${VERSION#"v"}
rm -Rf target/homebrew
mkdir -p target/homebrew/artifacts
echo "Targeting version $VERSION"
echo "Downloading macOS artifacts"
gh release download v$VERSION --pattern "Espanso-Mac*" --dir target/homebrew/artifacts
echo "Reading artifacts hashes"
INTEL_SHA=$(cat target/homebrew/artifacts/Espanso-Mac-Intel.zip.sha256.txt | awk -F ' ' '{print $1}')
M1_SHA=$(cat target/homebrew/artifacts/Espanso-Mac-M1.zip.sha256.txt | awk -F ' ' '{print $1}')
echo "Cloning tap repository"
pushd target/homebrew
git clone git@github.com:espanso/homebrew-espanso.git
pushd homebrew-espanso
echo "Rendering formula template"
cat ../../../scripts/resources/macos/formula_template.rb | sed "s/{{{VERSION}}}/$VERSION/g" | \
sed "s/{{{INTEL_SHA}}}/$INTEL_SHA/g" | sed "s/{{{M1_SHA}}}/$M1_SHA/g" > ./Casks/espanso.rb
echo "Committing version update"
git add Casks/espanso.rb
git commit -m "Version bump: $VERSION"
echo "Pushing changes"
git push
echo "Done!"

View File

@ -0,0 +1,19 @@
cask "espanso" do
version "{{{VERSION}}}"
if Hardware::CPU.intel?
url "https://github.com/federico-terzi/espanso/releases/download/v#{version}/Espanso-Mac-Intel.zip"
sha256 "{{{INTEL_SHA}}}"
else
url "https://github.com/federico-terzi/espanso/releases/download/v#{version}/Espanso-Mac-M1.zip"
sha256 "{{{M1_SHA}}}"
end
name "Espanso"
desc "A Privacy-first, Cross-platform Text Expander"
homepage "https://espanso.org/"
app "Espanso.app"
zap trash: "~/Library/Caches/espanso"
end

View File

@ -1,5 +1,5 @@
name: espanso name: espanso
version: 2.1.2-alpha version: 2.1.3-alpha
summary: A Cross-platform Text Expander written in Rust summary: A Cross-platform Text Expander written in Rust
description: | description: |
espanso is a Cross-platform, Text Expander written in Rust. espanso is a Cross-platform, Text Expander written in Rust.