JohnSundell / Marathon

[DEPRECATED] Marathon makes it easy to write, run and manage your Swift scripts πŸƒ
MIT License
1.86k stars 78 forks source link

Autocompletions for fish shell #83

Closed cojoj closed 7 years ago

cojoj commented 7 years ago

This PR closes #74

As discussed with @JohnSundell in #74 - it's super cool to have autocompletions in shells, so it's way easier to use tool. I've added very basic for of autocompletions for fish shell.

zrzut ekranu 2017-05-31 o 19 56 22

During the development of this feature I was hoping to find a universal solution, but in the end I think what we currently have is simply an overkill πŸ˜‚ Let me tell you why... (But there's a place for some nice refactoring, cause what I did is a code duplication. We can standardize it, extract it and make it way nicer)


The most popular shells are (I guess): bash, zsh and fish. In that case making something super generic and fully automatic is just a something we shouldn't spend much time.

Secondly, shells like fish and zsh (AFAIR) are interactive, so you have a lot of nice features available there which we simply can't use, cause we're generating scripts, so we assume they're really repetitive, right? Example: in fish you can specify behavior of the completion based on passed parameters and also specify the results via different command. In case of Marathon when we call completion on marathon remove it will suggest only installed packages at .marathon/Scripts/Cached - COOL, HUH? 😎

Last, but not least, when someone will want to contribute to this... Well... It's hard to get easily what's happening, cause we're escaping string and blah, blah, blah...


If you take a look at the file I had to write to generate marathon.fish and on marathon.fish directly...

internal final class FishAutocompleteInstaller {
    static func installIfNeeded(in folder: Folder) {
        do {
            guard !folder.containsSubfolder(named: "fish") else {
                return
            }

            let zshFolder = try folder.createSubfolder(named: "fish")
            let autocompleteFile = try zshFolder.createFile(named: "marathon.fish")

            var autocompleteCode = generateFishFunctions()

            for command in Command.all {
                autocompleteCode.append("complete -f -c marathon " +
                        "-n '__fish_marathon_needs_command' " +
                        "-a '\(command.rawValue)' " +
                        "-d '\(command.description)'" +
                        "\n")
            }

            try autocompleteFile.write(string: autocompleteCode)
        } catch {
            // Since this operation isn't critical, we silently fail if an error occur
        }
    }

    fileprivate static func generateFishFunctions() -> String {
        let needsCommand =  "function __fish_marathon_needs_command\n" +
                            "\tset cmd (commandline -opc)\n" +
                            "\tif [ (count $cmd) -eq 1 ]\n" +
                            "\t\treturn 0\n" +
                            "\tend\n" +
                            "\treturn 1\n" +
                            "end" +
                            "\n\n"

        return needsCommand
    }
}
function __fish_marathon_needs_command
    set cmd (commandline -opc)
    if [ (count $cmd) -eq 1 ]
        return 0
    end
    return 1
end

complete -f -c marathon -n '__fish_marathon_needs_command' -a 'create' -d 'Create new script at a given path and open it'
complete -f -c marathon -n '__fish_marathon_needs_command' -a 'edit' -d 'Edit a script at a given path'
complete -f -c marathon -n '__fish_marathon_needs_command' -a 'remove' -d 'Remove a package or the cache data for a script at a given path'
complete -f -c marathon -n '__fish_marathon_needs_command' -a 'run' -d 'Run a script at a given path'
complete -f -c marathon -n '__fish_marathon_needs_command' -a 'install' -d 'Install a script at a given path or URL as a binary'
complete -f -c marathon -n '__fish_marathon_needs_command' -a 'add' -d 'Add a package from a given URL to be able to use it from your scripts'
complete -f -c marathon -n '__fish_marathon_needs_command' -a 'list' -d 'List all packages and cached script data'
complete -f -c marathon -n '__fish_marathon_needs_command' -a 'update' -d 'Update all added packages to their latest versions'
complete -f -c marathon -n '__fish_marathon_needs_command' -a 'help' -d 'Print these instructions'

Simple math: 38 lines vs 17 lines I do realize that maintaining bash scripts isn't so cool compared to writing Swift scripts, but you get my point πŸ˜‰ Also, this will require manual updates to each completions file just to make them work with the latest Marathon version, but still, I thinks it'll be a simpler solution πŸ˜‰

Let me know what do you think... ✌️

cojoj commented 7 years ago

@JohnSundell I've changed the name (as discussed) and added unit test to check for existence πŸ˜‰