getpelican / pelican

Static site generator that supports Markdown and reST syntax. Powered by Python.
https://getpelican.com
GNU Affero General Public License v3.0
12.58k stars 1.81k forks source link

Add Bash, Fish... autocompletion? #2153

Closed jorgesumle closed 6 years ago

jorgesumle commented 7 years ago

Pelican is usually executed from the command-line, so it make sense to have autocompletion for command-line arguments. One Python program which has autocompletion and is installed with pip is youtube-dl. We could store the autocompletion files in pelican/pelican/tools/.

justinmayer commented 7 years ago

Great idea, Jorge. And thanks for mentioning Fish (my preferred shell). 🐟

Is this something you would be willing to help implement?

jorgesumle commented 7 years ago

Is this something you would be willing to help implement?

Yes, I'll try to make a pull request.

jorgesumle commented 7 years ago

Things to do (am I missing something?):

I wrote the script to generate the Bash autocompletion (bash-completion.py), the goal was to make it simple and don't change the Pelican core just for that.

The problem is that we need to execute it before a new version of Pelican is published. A Makefile would be useful for that, but I'm not the Pelican packager and I think they should decide how to automate the process. Once the completion files are generated, we could execute setup.py.

bash-completion.py

#!/usr/bin/env python
from __future__ import unicode_literals

import ast
import os
from os.path import dirname as dirn
import sys

import pelican

sys.path.insert(0, dirn(dirn((os.path.abspath(__file__)))))

BASH_COMPLETION_FILE = "pelican.bash-completion"
BASH_COMPLETION_TEMPLATE = "bash_completion.in"

def build_completion(options):
    with open(BASH_COMPLETION_TEMPLATE) as f:
        template = f.read()
    with open(BASH_COMPLETION_FILE, "w") as f:
        # just using the special char
        filled_template = template.replace("{{flags}}", " ".join(options))
        f.write(filled_template)

arguments_namespace = pelican.parse_arguments()
dict_args = vars(arguments_namespace)

pelican_options = ['--help', '--version']
for key in dict_args.keys():
    pelican_options.append('--' + key)

build_completion(pelican_options)

bash_completion.in

__pelican()
{
    local cur prev opts fileopts diropts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="{{flags}}"
    diropts="-o|--output|-t|--theme|-w|--write-selected"
    fileopts="-s|--settings"

    if [[ ${prev} =~ ${fileopts} ]]; then
        COMPREPLY=( $(compgen -f -- ${cur}) )
        return 0
    elif [[ ${prev} =~ ${diropts} ]]; then
        COMPREPLY=( $(compgen -d -- ${cur}) )
        return 0
    fi

    if [[ ${cur} == * ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}

complete -F __pelican pelican

The generated file after executing the script (pelican.bash-completion)

__pelican()
{
    local cur prev opts fileopts diropts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="--help --version --cache_path --ignore_cache --relative_paths --delete_outputdir --path --autoreload --output --fatal --theme --verbosity --selected_paths --settings"
    diropts="-o|--output|-t|--theme|-w|--write-selected"
    fileopts="-s|--settings"

    if [[ ${prev} =~ ${fileopts} ]]; then
        COMPREPLY=( $(compgen -f -- ${cur}) )
        return 0
    elif [[ ${prev} =~ ${diropts} ]]; then
        COMPREPLY=( $(compgen -d -- ${cur}) )
        return 0
    fi

    if [[ ${cur} == * ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}

complete -F __pelican pelican
jorgesumle commented 6 years ago

I learnt that it won't get installed correctly with pip, so I'll close this. I added the code to the wiki in case someone wants to make use of it.