air-verse / air

☁️ Live reload for Go apps

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Make pre_cmd background forkable

omani opened this issue · comments

Im trying to use
pre_cmd = ["/usr/bin/xdotool sleep 1 search --onlyvisible --classname Navigator windowactivate --sync key F5 &"]

to refresh the browser once the binary (golang echo framework) started. hence the sleep so the refresh happens after the http listening on the port is available.

I need to put the xdotool command into background & because otherwise air will wait for the command to finish and then run the webserver. which will obviously fail.

I checked the code for the runner. it seems that forking into background exits the process immediately (the exec commad in utils_linux.go is "/bin/sh -c"...so ofc air wont wait and dismiss the command right away.

so my question is:
any chance to implement a background forkable pre_cmd and the appropriate directive in air.toml?

I solved this issue by moving the command invocation into my main:go (where I start the echo webserver):

cmd := exec.Command("/usr/bin/xdotool", "search", "--onlyvisible", "--classname", "Navigator", "key", "F5")
err := cmd.Start()
if err != nil {
   log.Printf("Failed to start cmd: %v", err)
} else {
   if err := cmd.Wait(); err != nil {
	log.Printf("Cmd returned error: %v", err)
}
}

this refreshes the browser WITHOUT leaving neovim and losing focus from the IDE.

feel free to close this issue if you are not interested in implementing a forkable pre_cmd for air.

I have a similar solution for hot-reloading the code with air, but I used goroutines.

refresh.sh

set -o errexit
set -o nounset

keystroke="CTRL+F5"
browser="${1:-firefox}"

# find all visible browser windows
browser_windows="$(xdotool search --sync --all --onlyvisible --name ${browser})"

# Send keystroke
for bw in $browser_windows; do
    xdotool key --window "$bw" "$keystroke"
done

In my main.go file, I run the .sh file and the listen command as goroutines.

main.go

// ... other code

func main() {
    // Locate .sh file
    cmd := exec.Command("/bin/sh", "refresh.sh")

    engine := html.New("./views", ".html")

    app := fiber.New(fiber.Config{
	Views: engine,
    })

    app.Static("/", "./public")

    app.Get("/", func(c *fiber.Ctx) error {
	return c.Render("index", fiber.Map{
		"title": "Hello, World!",
	}, "layouts/main")
    })

    // Run both the refresh command and start the app
    go cmd.Run()
    go log.Fatal(app.Listen(":3000"))
}

The main drawback with this refresh command is that it will only refresh the current, visible tab. So it won't refresh the working page unless it's open. I wish there was a way to refresh the working tab even when it's not visible.

The main drawback with this refresh command is that it will only refresh the current, visible tab. So it won't refresh the working page unless it's open. I wish there was a way to refresh the working tab even when it's not visible.

for me this is ok since I only work with the browser page/tab open side by side to my neovim environment, so I can see the changes immediately when eg. working on the tailwindcss part.

for now Im happy with this solution.