Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(espanso): support custom path #13977

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions extensions/espanso/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Espanso Changelog

# [Path Configuration] - {PR_MERGE_DATE}

- Add a preference to configure the path to the Espanso executable
- Explicitly set the path to the Espanso executable as `/opt/homebrew/bin/espanso` for Apple Silicon macs and `/usr/local/bin/espanso` for Intel macs

## [Patch] - 2024-07-09

- Remove form items from the list.
Expand Down
977 changes: 369 additions & 608 deletions extensions/espanso/package-lock.json

Large diffs are not rendered by default.

28 changes: 19 additions & 9 deletions extensions/espanso/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@
"icon": "espanso-logo.png",
"author": "kud",
"contributors": [
"nbbaier"
"nbbaier",
"erics118"
],
"categories": [
"Applications",
"System",
"Productivity"
],
"license": "MIT",
"preferences": [
{
"name": "espansoPath",
"type": "textfield",
"required": false,
"title": "Espanso CLI Path",
"description": "Location to the Espanso CLI (Defaults to `/opt/homebrew/bin/espanso` on Apple Silicon Macs, and `/usr/local/bin/espanso` otherwise)"
}
],
"commands": [
{
"name": "index",
Expand Down Expand Up @@ -52,25 +62,25 @@
}
],
"dependencies": {
"@raycast/api": "^1.61.1",
"@raycast/utils": "^1.10.0",
"@raycast/api": "^1.80.0",
"@raycast/utils": "^1.16.3",
"change-case": "5.4.4",
"fs-extra": "^11.1.1",
"zx": "7.2.3"
"yaml": "^2.5.0"
},
"devDependencies": {
"@raycast/eslint-config": "1.0.8",
"@types/node": "20.8.10",
"@types/react": "18.2.34",
"@types/node": "^20.14.12",
"@types/react": "^18.3.3",
"eslint": "^8.53.0",
"prettier": "^3.0.3",
"typescript": "^5.2.2"
"prettier": "^3.3.3",
"typescript": "^5.5.4"
},
"scripts": {
"build": "ray build -e dist",
"dev": "ray develop",
"fix-lint": "ray lint --fix",
"lint": "ray lint",
"prepublishOnly": "echo \"\\n\\nIt seems like you are trying to publish the Raycast extension to npm.\\n\\nIf you did intend to publish it to npm, remove the \\`prepublishOnly\\` script and rerun \\`npm publish\\` again.\\nIf you wanted to publish it to the Raycast Store instead, use \\`npm run publish\\` instead.\\n\\n\" && exit 1",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓Does it come from a new version of Raycast?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is from a newer version of the template that I copied over

"publish": "npx @raycast/api@latest publish"
}
}
15 changes: 1 addition & 14 deletions extensions/espanso/src/content/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ It seems like the Espanso command-line tool is not currently installed on your s

Please follow these steps to install Espanso:

For MacOS:

1. Open Terminal.

2. Install Homebrew by pasting the following command and pressing Enter:
Expand All @@ -38,18 +36,7 @@ brew install espanso
\`\`\`
4. Verify the installation by typing \`espanso\` in the terminal. If the installation was successful, you'll see information about how to use Espanso.

For Windows:
1. Download the latest Espanso installer from the official website: https://espanso.org/install/
2. Run the installer and follow the on-screen instructions.
3. Verify the installation by opening PowerShell and typing \`espanso\`. If the installation was successful, you'll see information about how to use Espanso.

For Linux:
1. Open Terminal.
2. Depending on your distribution, use the appropriate command to install Espanso. For example, on Debian-based distributions (like Ubuntu), you'd use:
\`\`\`
sudo apt install espanso
\`\`\`
3. Verify the installation by typing \`espanso\` in the terminal. If the installation was successful, you'll see information about how to use Espanso.
If there are still issues with the installation, try adding the output of \`which espanso\` to the \`Espanso CLI Path\` extension preference.

Remember to restart your computer after the installation process. If you need more detailed instructions, please refer to the official Espanso installation guide at https://espanso.org/install/.
`;
6 changes: 3 additions & 3 deletions extensions/espanso/src/disable.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { showHUD } from "@raycast/api";
import { $ } from "zx";
import { espansoCli } from "./lib/espanso";

export default async function main() {
try {
await $`espanso cmd disable`;
await showHUD("Espanso disable");
await espansoCli("cmd disable");
await showHUD("Espanso disabled");
} catch (error) {
await showHUD(`Error: ${error}`);
}
Expand Down
4 changes: 2 additions & 2 deletions extensions/espanso/src/enable.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { showHUD } from "@raycast/api";
import { $ } from "zx";
import { espansoCli } from "./lib/espanso";

export default async function main() {
try {
await $`espanso cmd enable`;
await espansoCli("cmd enable");
await showHUD("Espanso enabled");
} catch (error) {
await showHUD(`Error: ${error}`);
Expand Down
12 changes: 6 additions & 6 deletions extensions/espanso/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Application, Detail, List, getFrontmostApplication } from "@raycast/api";
import { useEffect, useState } from "react";
import { ProcessOutput } from "zx";
import { capitalCase, kebabCase } from "change-case";

import { commandNotFoundMd, noContentMd } from "./content/messages";
Expand All @@ -17,7 +16,7 @@ export default function Command() {
const [filteredItems, setFilteredItems] = useState<FormattedMatch[]>([]);
const [categories, setCategories] = useState<string[]>([]);
const [selectedCategory, setSelectedCategory] = useState<string>("all");
const [error, setError] = useState<ProcessOutput | null>(null);
const [error, setError] = useState<string | null>(null);
const [application, setApplication] = useState<Application | undefined>(undefined);

useEffect(() => {
Expand Down Expand Up @@ -75,8 +74,9 @@ export default function Command() {
setFilteredItems(formattedMatches);
setCategories(["all", ...sortedCategories]);
setIsLoading(false);
} catch (err) {
setError(err instanceof ProcessOutput ? err : null);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) {
setError("message" in err ? (err.message as string) : null);
setIsLoading(false);
}
};
Expand All @@ -89,8 +89,8 @@ export default function Command() {
}, [selectedCategory, items]);

if (error) {
const notFound = /command not found/.test(error.stderr);
return <Detail markdown={notFound ? commandNotFoundMd : error.stderr} />;
const notFound = /No such file or directory/.test(error);
return <Detail markdown={notFound ? commandNotFoundMd : error} />;
}

if (!isLoading && items.length === 0) {
Expand Down
29 changes: 29 additions & 0 deletions extensions/espanso/src/lib/espanso.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { getPreferenceValues } from "@raycast/api";
import { arch } from "os";
import { exec } from "child_process";

function execAsync(command: string): Promise<{ stdout: string; stderr: string }> {
return new Promise((resolve, reject) => {
exec(command, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
resolve({ stdout, stderr });
});
});
}
Comment on lines +3 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like

import { exec } from "child_process";
import { promisify } from "util";

const execAsync = promisify(exec);

could be probably better.


export async function espansoCli(args: string) {
const preferences = getPreferenceValues<Preferences>();

const espansoPath: string = preferences.espansoPath?.length
? preferences.espansoPath
: arch() === "arm64"
? "/opt/homebrew/bin/espanso"
: "/usr/local/bin/espanso";
Comment on lines +23 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we could test first if it exists because not everyone installs it via homebrew.

Wonder if we could check first if the shortcut command espanso exists and once it does not exist, test first the preference and then the homebrew version.


const res = await execAsync(`${espansoPath} ${args}`);

return res;
}
21 changes: 10 additions & 11 deletions extensions/espanso/src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import fse from "fs-extra";
import fs from "node:fs";
import path from "path";
import { $ } from "zx";
import { EspansoMatch, MultiTrigger, Label, Replacement, NormalizedEspansoMatch, EspansoConfig } from "./types";
import YAML from "yaml";
$.verbose = false;
import { espansoCli } from "./espanso";

function lastUpdatedDate(file: string) {
const { mtime } = fse.statSync(file);
const { mtime } = fs.statSync(file);

return mtime.getTime();
}

export function getAndSortTargetFiles(espansoMatchDir: string): { file: string; mtime: number }[] {
const targetFiles = fse
const targetFiles = fs
.readdirSync(espansoMatchDir, { withFileTypes: true })
.filter((dirent: fse.Dirent) => dirent.isFile() && path.extname(dirent.name).toLowerCase() === ".yml");
.filter((dirent: fs.Dirent) => dirent.isFile() && path.extname(dirent.name).toLowerCase() === ".yml");

const matchFilesTimes = targetFiles.map((targetFile) => {
return { file: targetFile.name, mtime: lastUpdatedDate(path.join(espansoMatchDir, targetFile.name)) };
Expand All @@ -35,7 +34,7 @@ export function formatMatch(espansoMatch: MultiTrigger & Label & Replacement) {

export function appendMatchToFile(fileContent: string, fileName: string, espansoMatchDir: string) {
const filePath = path.join(espansoMatchDir, fileName);
fse.appendFileSync(filePath, fileContent);
fs.appendFileSync(filePath, fileContent);

return { fileName, filePath };
}
Expand All @@ -44,15 +43,15 @@ export function getMatches(espansoMatchDir: string, options?: { packagePath: boo
const finalMatches: NormalizedEspansoMatch[] = [];

function readDirectory(dir: string) {
const items = fse.readdirSync(dir, { withFileTypes: true });
const items = fs.readdirSync(dir, { withFileTypes: true });

for (const item of items) {
const fullPath = path.join(dir, item.name);

if (item.isDirectory()) {
if (options?.packagePath) {
const packageFilePath = path.join(fullPath, "package.yml");
if (fse.existsSync(packageFilePath) && fse.statSync(packageFilePath).isFile()) {
if (fs.existsSync(packageFilePath) && fs.statSync(packageFilePath).isFile()) {
processFile(packageFilePath);
}
} else {
Expand All @@ -65,7 +64,7 @@ export function getMatches(espansoMatchDir: string, options?: { packagePath: boo
}

function processFile(filePath: string) {
const content = fse.readFileSync(filePath);
const content = fs.readFileSync(filePath);
const { matches = [] }: { matches?: EspansoMatch[] } = YAML.parse(content.toString()) || {};

finalMatches.push(
Expand Down Expand Up @@ -99,7 +98,7 @@ export async function getEspansoConfig(): Promise<EspansoConfig> {
match: "",
};

const { stdout: configString } = await $`espanso path`;
const { stdout: configString } = await espansoCli("path");

configString.split("\n").forEach((item) => {
const [key, value] = item.split(":");
Expand Down
4 changes: 2 additions & 2 deletions extensions/espanso/src/toggle.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { showHUD } from "@raycast/api";
import { $ } from "zx";
import { espansoCli } from "./lib/espanso";

export default async function main() {
try {
await $`espanso cmd toggle`;
await espansoCli("cmd toggle");
await showHUD("Espanso toggled");
} catch (error) {
await showHUD(`Error: ${error}`);
Expand Down
14 changes: 4 additions & 10 deletions extensions/espanso/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Node 16",
"include": [
"src/**/*",
"raycast-env.d.ts"
],
"include": ["src/**/*", "raycast-env.d.ts"],
"compilerOptions": {
"lib": [
"es2021"
],
"lib": ["ES2023"],
"module": "commonjs",
"target": "es2021",
"target": "ES2022",
"strict": true,
"isolatedModules": true,
"esModuleInterop": true,
Expand All @@ -19,4 +13,4 @@
"jsx": "react-jsx",
"resolveJsonModule": true
}
}
}
Loading