Skip to content

Commit

Permalink
fix(editors): adding windsurf. Cleaning up runScriptlet
Browse files Browse the repository at this point in the history
  • Loading branch information
John Lindquist committed Dec 13, 2024
1 parent 67149aa commit bd168f2
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 107 deletions.
4 changes: 2 additions & 2 deletions build/build-kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,14 @@ if (existsSync(kitEditorDtsPath)) {
}

console.log(`Building ESM to ${kitPath()}`);
await exec(`npx tsc --outDir ${kitPath()}`).catch((e) => {
await exec(`pnpm exec tsc --outDir ${kitPath()}`).catch((e) => {
console.error(e);
process.exit(1);
});

console.log(`Building declarations to ${kitPath()}`);
await exec(
`npx tsc --project ./tsconfig-declaration.json --outDir ${kitPath()}`
`pnpm exec tsc --project ./tsconfig-declaration.json --outDir ${kitPath()}`
).catch((e) => {
console.error(e);
process.exit(1);
Expand Down
239 changes: 135 additions & 104 deletions src/main/scriptlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,27 +71,7 @@ export let runScriptlet = async (
flag
)

const unixPattern = /\$\{?(\d+)\}?/g
const windowsPattern = /%(\d+)/g

const matches =
formattedScriptlet.match(unixPattern) ||
formattedScriptlet.match(windowsPattern)

const matchesSet = new Set(matches || [])
const needs = focusedScriptlet?.tool === "template" ? remainingInputs : [...(matches || []), ...remainingInputs];


for (let need of needs) {
let result = await arg(need)
if (matchesSet.has(need)) {
// For matches (Unix/Windows patterns), replace directly
formattedScriptlet = formattedScriptlet.replace(need, result)
} else {
// For inputs, wrap in curly braces before replacing
formattedScriptlet = formattedScriptlet.replaceAll(`{{${need}}}`, result)
}
}
formattedScriptlet = await replacePlaceholders(formattedScriptlet, focusedScriptlet, remainingInputs)

if (process.env.KIT_CONTEXT === "app") {
send(Channel.STAMP_SCRIPT, focusedScriptlet as Script)
Expand All @@ -105,112 +85,163 @@ export let runScriptlet = async (
case "kit":
case "ts":
case "js": {
const quickPath = kenvPath(
"tmp",
`scriptlet-${formattedFocusedScriptlet.command}.ts`
)
await writeFile(quickPath, formattedScriptlet)
return await run(quickPath)
return await handleJsTsKitScriptlet(formattedFocusedScriptlet, formattedScriptlet)
}
case "transform": {
const quickPath = kenvPath(
"tmp",
`scriptlet-${formattedFocusedScriptlet.command}.ts`
)
const content = `let text = await getSelectedText()
let result = ${formattedScriptlet}
await setSelectedText(result)`
await writeFile(quickPath, content)
return await run(quickPath)
return await handleTransformScriptlet(formattedFocusedScriptlet, formattedScriptlet)
}
case "template": {
const result = await template(formattedScriptlet, {
shortcuts: [
{
name: "Submit",
key: `${cmd}+s`,
bar: "right",
onPress: (input) => {
submit(input)
}
}
]
});
await setSelectedText(result)
process.exit(0)
await handleTemplateScriptlet(formattedScriptlet)
break
}
case "open":
case "edit":
case "paste":
case "type": {
await hide()
if (formattedFocusedScriptlet.tool === "open") {
await open(formattedScriptlet)
await wait(1000)
} else if (formattedFocusedScriptlet.tool === "edit") {
await edit(formattedScriptlet)
await wait(1000)
} else if (formattedFocusedScriptlet.tool === "paste") {
await setSelectedText(formattedScriptlet)
} else if (formattedFocusedScriptlet.tool === "type") {
await keyboard.type(formattedScriptlet)
}
process.exit(0)
await handleActionScriptlet(formattedFocusedScriptlet, formattedScriptlet)
break
}
default: {
const extension =
toolExtensionMap.get(formattedFocusedScriptlet.tool) ||
formattedFocusedScriptlet.tool
const scriptPath = kenvPath(
"tmp",
`scriptlet-${formattedFocusedScriptlet.command}.${extension}`
)
await writeFile(scriptPath, formattedScriptlet)

const commandGenerator = toolCommandMap.get(
formattedFocusedScriptlet.tool
)
if (!commandGenerator) {
throw new Error(`Unsupported tool: ${formattedFocusedScriptlet.tool}`)
}
return await handleDefaultScriptlet(formattedFocusedScriptlet, formattedScriptlet)
}
}
}

let command = commandGenerator(scriptPath)
// Replaces placeholders in the scriptlet with user inputs
async function replacePlaceholders(formattedScriptlet: string, focusedScriptlet: Scriptlet, remainingInputs: string[]): Promise<string> {
const unixPattern = /\$\{?(\d+)\}?/g
const windowsPattern = /%(\d+)/g

if (formattedFocusedScriptlet.prepend) {
command = `${formattedFocusedScriptlet.prepend} ${command}`
}
const matches =
formattedScriptlet.match(unixPattern) ||
formattedScriptlet.match(windowsPattern)

const matchesSet = new Set(matches || [])
const needs = focusedScriptlet?.tool === "template" ? remainingInputs : [...(matches || []), ...remainingInputs];

if (formattedFocusedScriptlet.append) {
command = `${command} ${formattedFocusedScriptlet.append}`
}

const cwd = formattedFocusedScriptlet?.cwd
? slash(untildify(formattedFocusedScriptlet.cwd))
: undefined
for (let need of needs) {
let result = await arg(need)
if (matchesSet.has(need)) {
// For matches (Unix/Windows patterns), replace directly
formattedScriptlet = formattedScriptlet.replace(need, result)
} else {
// For inputs, wrap in curly braces before replacing
formattedScriptlet = formattedScriptlet.replaceAll(`{{${need}}}`, result)
}
}
return formattedScriptlet
}

const useExec =
SHELL_TOOLS.includes(formattedFocusedScriptlet.tool) &&
!formattedFocusedScriptlet.term
// Handles scriptlets with "kit", "ts", or "js" tools
async function handleJsTsKitScriptlet(formattedFocusedScriptlet: Scriptlet, formattedScriptlet: string) {
const quickPath = kenvPath(
"tmp",
`scriptlet-${formattedFocusedScriptlet.command}.ts`
)
await writeFile(quickPath, formattedScriptlet)
return await run(quickPath)
}

if (process.env.KIT_CONTEXT === "app") {
if (!useExec) {
return await term({ command, cwd })
}
// Handles scriptlets with the "transform" tool
async function handleTransformScriptlet(formattedFocusedScriptlet: Scriptlet, formattedScriptlet: string) {
const quickPath = kenvPath(
"tmp",
`scriptlet-${formattedFocusedScriptlet.command}.ts`
)
const content = `let text = await getSelectedText()
let result = ${formattedScriptlet}
await setSelectedText(result)`
await writeFile(quickPath, content)
return await run(quickPath)
}

if (formattedFocusedScriptlet.shebang) {
const shebang = parseShebang(formattedFocusedScriptlet)
return await sendWait(Channel.SHEBANG, shebang)
// Handles scriptlets with the "template" tool
async function handleTemplateScriptlet(formattedScriptlet: string) {
const result = await template(formattedScriptlet, {
shortcuts: [
{
name: "Submit",
key: `${cmd}+s`,
bar: "right",
onPress: (input) => {
submit(input)
}
}
]
});
await setSelectedText(result)
process.exit(0)
}

return await exec(command, {
shell: true,
stdio: "inherit",
cwd,
windowsHide: true
})
// Handles scriptlets with "open", "edit", "paste", or "type" tools
async function handleActionScriptlet(formattedFocusedScriptlet: Scriptlet, formattedScriptlet: string) {
await hide()
if (formattedFocusedScriptlet.tool === "open") {
await open(formattedScriptlet)
await wait(1000)
} else if (formattedFocusedScriptlet.tool === "edit") {
await edit(formattedScriptlet)
await wait(1000)
} else if (formattedFocusedScriptlet.tool === "paste") {
await setSelectedText(formattedScriptlet)
} else if (formattedFocusedScriptlet.tool === "type") {
await keyboard.type(formattedScriptlet)
}
process.exit(0)
}

// Handles scriptlets with other tools (e.g., "bash", "python", etc.)
async function handleDefaultScriptlet(formattedFocusedScriptlet: Scriptlet, formattedScriptlet: string) {
const extension =
toolExtensionMap.get(formattedFocusedScriptlet.tool) ||
formattedFocusedScriptlet.tool
const scriptPath = kenvPath(
"tmp",
`scriptlet-${formattedFocusedScriptlet.command}.${extension}`
)
await writeFile(scriptPath, formattedScriptlet)

const commandGenerator = toolCommandMap.get(
formattedFocusedScriptlet.tool
)
if (!commandGenerator) {
throw new Error(`Unsupported tool: ${formattedFocusedScriptlet.tool}`)
}

let command = commandGenerator(scriptPath)

if (formattedFocusedScriptlet.prepend) {
command = `${formattedFocusedScriptlet.prepend} ${command}`
}

if (formattedFocusedScriptlet.append) {
command = `${command} ${formattedFocusedScriptlet.append}`
}

const cwd = formattedFocusedScriptlet?.cwd
? slash(untildify(formattedFocusedScriptlet.cwd))
: undefined

const useExec =
SHELL_TOOLS.includes(formattedFocusedScriptlet.tool) &&
!formattedFocusedScriptlet.term

if (process.env.KIT_CONTEXT === "app") {
if (!useExec) {
return await term({ command, cwd })
}

if (formattedFocusedScriptlet.shebang) {
const shebang = parseShebang(formattedFocusedScriptlet)
return await sendWait(Channel.SHEBANG, shebang)
}
}

return await exec(command, {
shell: true,
stdio: "inherit",
cwd,
windowsHide: true
})
}
19 changes: 18 additions & 1 deletion src/platform/darwin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "../core/utils.js"

import { refreshScripts } from "../core/db.js"
import { existsSync } from "fs"

global.applescript = async (script, options = { silent: true }) => {
let applescriptPath = kenvTmpPath("latest.scpt")
Expand Down Expand Up @@ -174,7 +175,23 @@ global.selectKitEditor = async (reset = false) => {

let possibleEditors = () => {
let filteredMacEditors = macEditors
.map((editor) => globalBins.find(({ name }) => name === editor))
.map((editor) => {
if (editor === "windsurf") {
const windsurfPath = "/Users/johnlindquist/.codeium/windsurf/bin/windsurf"
try {
if (existsSync(windsurfPath)) {
return {
name: "windsurf",
description: windsurfPath,
value: windsurfPath
}
}
} catch (error) {
// Ignore error if path doesn't exist
}
}
return globalBins.find(({ name }) => name === editor)
})
.filter(Boolean)

filteredMacEditors.push({
Expand Down

0 comments on commit bd168f2

Please sign in to comment.