TextToolsPro icon indicating copy to clipboard operation
TextToolsPro copied to clipboard

Import Espanso file via Tasker

Open quintrino opened this issue 8 months ago • 5 comments

Hi,

probably a niche feature request, but could you make the import functionality visible to Tasker? Either as a Plugin or as an intent.

I have my espanso file automatically synced from my desktop to my mobile, but at the moment I have to manually import it whenever I make any changes.

It would be great if that was accessible via Tasker as then I could automate it to occur regularly.

quintrino avatar Apr 01 '25 14:04 quintrino

Hi. Sure I’ll attempt it next update. Unfortunately I can’t do it soon because at the moment university is giving me a ton of work and im very tired. I’ll definitely give it a try next update.

lochidev avatar Apr 01 '25 16:04 lochidev

Thanks so much for even attempting it! Do you have a donate link somewhere?

quintrino avatar Apr 01 '25 22:04 quintrino

Yes, it’s in the readme. But please consider donating only after I add the feature because i only accept donations for work that have been already completed 😅.

lochidev avatar Apr 02 '25 01:04 lochidev

Well then I'll just donate for what you've already done and have another one ready to go if you do this.

quintrino avatar Apr 03 '25 09:04 quintrino

Well then I'll just donate for what you've already done and have another one ready to go if you do this.

Thank you so much! 💙

lochidev avatar Apr 03 '25 11:04 lochidev

Through System → Send Intent,

Use these parameters,

Field:   Action
Value:   com.dingleinc.texttoolspro.IMPORT_CONFIG

Field:   Extra
Value:   config_string:my test config

Field: Class
Value: com.dingleinc.texttoolspro.ConfigImportReceiver

Field:   Package
Value:   com.dingleinc.texttoolspro

Field:   Target
Value:   Broadcast Receiver

For feedback use,

Event: Intent Received
Action: com.dingleinc.texttoolspro.CONFIG_RESULT

Underlying code is

Intent resultIntent = new Intent("com.dingleinc.texttoolspro.CONFIG_RESULT");
resultIntent.PutExtra("status", 0); // 
context.SendBroadcast(resultIntent);

%status will be 0 if successfully imported, or else it will be an error string like "failed to import".

Keep in mind when you use this, everything will be replaced and saved by "my test config" (make sure this is valid YML) and nothing before that will be recoverable, so make sure you backup your files.

Please test using the build: https://github.com/lochidev/Expandroid/releases/tag/v7.2.1 and let me know if everything works. Thanks!

EDIT: You can now download the update on google play as well.

lochidev avatar Jul 18 '25 12:07 lochidev

so just to confirm, I should replace my test config with the file location of the espanso file? something like /storage/emulated/0/Sync/espanso.yml?

And it sounds like every import will wipe all the previous entries, so I couldn't import espanso.yml and private.yml?

quintrino avatar Jul 20 '25 03:07 quintrino

Due to scoped storage in newer android versions, the app cannot access any files without explicit user permission. Therefore, "my test config" expects the contents of the file and NOT the file path. I don't think it's possible to access it and I didn't even try because of scoped storage. You will have to concatenate the contents of the files and substitute that with "my test config". For example: "my test config" should be replaced by the CONTENT of example config.yml. So if you want to import two files you'll need to do some processing (in tasker this should be possible maybe? I haven't really used tasker much). However, just combining the contents of espanso.yml and private.yml might work in your case.

Something like:

config_string=matches:
- trigger: :date
  replace: '{{date}}'

lochidev avatar Jul 20 '25 11:07 lochidev

This is now functioning, and in my mind, complete. Thank you for making a long term dream of synchronised shortcuts a reality. I'm donating to your project now.

So for those looking for a fully automated system between your Android and Computer, here is how I have it working for me.

  1. Have your espanso shortcuts in a file that that syncs to your android

(most basic version would be symlinking into a Google drive folder and using something like AutoSync to get it on your Android) (Because I have multiple espanso files, I have a script that merges them all into a single file, and then uploads that to Google Drive)

  1. Set Tasker to regularly and automatically read that file, and then import it into Expandroid.

(Most basic is Profile every day at 5:00 / every hour / every minute. read the Espanso file on your android and save it as a variable. Have Expandroid import it using method above)

Please note that this means you'd have to add all new options into your epsanso conflg file on your computer, and then it would automatically import. Changes made directly in Expandroid would be lost on the next update.

if this doesn't make sense to someone trying to set this up, feel free to reach out and I'll use your questions to improve this description.

quintrino avatar Sep 08 '25 01:09 quintrino

Thank you so much for the donation and I'm glad to hear it works well. If you find any bugs, please let me know! ❤️

lochidev avatar Sep 08 '25 10:09 lochidev

I believe I've found a bug, but it seems to be in Tasker.

It seems that having Tasker read a file only loads 200~ lines as a variable.

I'll follow up with them and then confirm if it is actually local to Expandroid.

When you tested it, how large was the variable?

quintrino avatar Sep 09 '25 07:09 quintrino

So I use the intent.getStringExtra() function locally and it seems in android there is a 1 MB total transaction size limit. The variable used to store it is the C# string which shouldn't have any issues handling even larger strings. But 300 lines probably don't hit the 1 MB size limit per intent, so let's wait for the response from Tasker devs. Size of the string flew under my radar and it seems I'll have to make changes in my end as well if there is no way around it. What I'm planning to do is use multiple intents to build up a full config file made up of multiple parts, concatenated internally by my app itself, and after it receives another intent with an import command, proceed with importing the config.

lochidev avatar Sep 09 '25 09:09 lochidev

Okay, I posted here. https://www.reddit.com/r/tasker/comments/1nccxbz/comment/nd8yawg/

And it seems like the line limit is just in how Tasker displays variables, not stores them, so it seems it is an Expandroid bug.

Looking at my base file here. https://github.com/quintrino/dotfiles/blob/master/config/espanso/match/base.yml

It seems like

##########################
  - trigger: ":)"
    replace: "🙂"
  - trigger: ":p"
    replace: "😛"
  - trigger: ":P"
    replace: "😛"
  - trigger: ";)"
    replace: "😉"
  - trigger: ":("
    replace: "🙁"
  - trigger: ":D"
    replace: "😃"
  - trigger: "::p"
    replace: "{{output}}"
    vars:
      - name: output
        type: shell
        params:
          cmd: "pbpaste -o | tr ' ' '-'"
  - trigger: ":low"
    replace: "{{output}}"
    vars:
      - name: "clipboard"
        type: "clipboard"
      - name: output
        type: shell
        params:
          cmd: "echo $ESPANSO_CLIPBOARD | tr '[:upper:]' '[:lower:]'"
  - trigger: ":up"
    replace: "{{output}}"
    vars:
      - name: "clipboard"
        type: "clipboard"
      - name: output
        type: shell
        params:
          cmd: "echo $ESPANSO_CLIPBOARD | tr '[:lower:]' '[:upper:]'"
  - trigger: ":tableflip:"
    replace: "(╯°□°)╯︵ ┻━┻"
  - trigger: ":fliptable:"
    replace: "(╯°□°)╯︵ ┻━┻"
  - trigger: ":fixtable:"
    replace: "┬─┬ノ( º _ ºノ)"
  - trigger: ":shrug"
    replace: "¯\\_(ツ)_/¯"
  - trigger: ":st1"
    replace: "⭐"
  - trigger: ":st2"
    replace: "⭐⭐"
  - trigger: ":st3"
    replace: "⭐⭐⭐"
  - trigger: ":st4"
    replace: "⭐⭐⭐⭐"
  - trigger: ":st5"
    replace: "⭐⭐⭐⭐⭐"
  - regex: ":ml(?P<label>.*):"
    replace: "[{{label}}]({{clip}})"
    vars:
      - name: "clip"
        type: "clipboard"
  - trigger: ":gs"
    replace: "⚡GodSpeed"
#########################

Some of them I understand, because they use complicated functionality (such as output or regex) but some are just emoji, which work fine in regular input but not via Tasker.

And in my private.yml I have a number of just plain strings that don't seem to get imported either. One of them is

  - trigger: ":voice"
    replace: "+1 XXX XXX-XXXX "

and that doesn't load either.

and when I went into the file and changed

  - trigger: ":nwn"
    replace: Nick Wolf

to

  - trigger: ":nwn"
    replace: Nick Wolf Unlimited

and reimported via Tasker it didn't seem to overwrite the existing one.

Even when I delete the "Nick Wolf" one, and re-import it returns with "Nick Wolf" rather than "Nick Wolf Unlimited".

Happy to help you debug if that will be useful, just not sure how to get the debug logs.

quintrino avatar Sep 10 '25 14:09 quintrino

Image

Hi! As seen in the figure above, the troublemaker here is the regex entry. Notice that it doesn’t have a trigger like the others, and instead it uses "regex" instead of "trigger." My app’s data structures can’t handle that. Is there any possibility you could move your regex entries into a separate file on your PC? I’ve verified that base.yml works after removing the regex entry. Most of the time, the app can safely ignore unsupported features if a trigger is defined, but in this case, the regex has no trigger, so it’s causing errors.

My tasker config is attached below:

Image Image

lochidev avatar Sep 11 '25 15:09 lochidev

Okay, updating this comment with new new context.

The only issue was because I was merging two yml files together Expandroid didn't handle a second matches: line where the second file started, so I just filtered that out in Tasker, and now it seems like most other things are working.

quintrino avatar Sep 12 '25 22:09 quintrino

Thank you again for implementing this and helping debug it. 🙂

quintrino avatar Sep 12 '25 23:09 quintrino

Ok, it seems everything is fine now? 😅 Let me know if you need help with anything else!

lochidev avatar Sep 13 '25 06:09 lochidev

Yeah, I think the errors from the regex and the second "matches:" combined to make it hard to debug, but now they're both solved.

I was never able to get the com.dingleinc.texttoolspro.CONFIG_RESULT returning any useful data either on failure or success, but now that the import is working I think we're in the clear overall.

quintrino avatar Sep 13 '25 07:09 quintrino

Image

Hmmm, you don't receive a 0 after success? My tasker can receive feedback like in the figure above. Yes the errors are not very useful but you should get some error or success. The only case where this is not so is when config_string: is empty, in that case there will not be any feedback which was a mistake on my part now that I think about it 😂

lochidev avatar Sep 13 '25 12:09 lochidev

Hi, instead of using an intent wouldn't it be possible to just symlink a file to the location where the config file from expandroid is by exchanging the expandroid config file with the link?

For that I guess the name should be the same. In future by doing that maybe you could symlink the whole espanso folder in one go.

Would you share us the location of the config file, if that is a way?

Mintuen avatar Sep 20 '25 21:09 Mintuen

@Mintuen Right now, the app actually converts YML files into JSON and stores them for internal use, I think I did it for more reliability. So yeah, maybe in the future. See https://github.com/lochidev/Expandroid/blob/main/src/Models/AppSettings.cs

lochidev avatar Sep 21 '25 07:09 lochidev