Skip to content

Commit

Permalink
Added PlatformIO CLI Shell Completion for Fish, Zsh, Bash, and PowerS…
Browse files Browse the repository at this point in the history
…hell // Resolve #3435
  • Loading branch information
ivankravets committed May 10, 2020
1 parent 03228c5 commit 01a1981
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 3 deletions.
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ PlatformIO Core 4
4.3.4 (2020-??-??)
~~~~~~~~~~~~~~~~~~

* Added `PlatformIO CLI Shell Completion <https://docs.platformio.org/page/core/userguide/misc/completion/index.html>`__ for Fish, Zsh, Bash, and PowerShell (`issue #3435 <https://github.com/platformio/platformio-core/issues/3435>`_)
* Automatically build ``contrib-pysite`` package on a target machine when pre-built package is not compatible (`issue #3482 <https://github.com/platformio/platformio-core/issues/3482>`_)

4.3.3 (2020-04-28)
Expand Down
7 changes: 7 additions & 0 deletions platformio/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@
from platformio.commands import PlatformioCLI
from platformio.compat import CYGWIN

try:
import click_completion # pylint: disable=import-error

click_completion.init()
except: # pylint: disable=bare-except
pass


@click.command(
cls=PlatformioCLI, context_settings=dict(help_option_names=["-h", "--help"])
Expand Down
2 changes: 1 addition & 1 deletion platformio/commands/home/rpc/handlers/piocore.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ def get_value_and_reset(self):
result = ""
try:
result = self.getvalue()
self.truncate(0)
self.seek(0)
self.truncate(0)
except AttributeError:
pass
return result
Expand Down
13 changes: 13 additions & 0 deletions platformio/commands/misc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2014-present PlatformIO <[email protected]>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
96 changes: 96 additions & 0 deletions platformio/commands/misc/command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright (c) 2014-present PlatformIO <[email protected]>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import subprocess

import click

from platformio import proc
from platformio.commands.misc.completion import (
get_completion_install_path,
install_completion_code,
uninstall_completion_code,
)


@click.group("misc", short_help="Miscellaneous commands")
def cli():
pass


@cli.group("completion", short_help="Shell completion support")
def completion():
# pylint: disable=import-outside-toplevel
try:
import click_completion # pylint: disable=import-error,unused-import
except ImportError:
click.echo("Installing dependent packages...")
subprocess.check_call(
[proc.get_pythonexe_path(), "-m", "pip", "install", "click-completion"],
)


@completion.command("install", short_help="Install shell completion files/code")
@click.option(
"--shell",
default=None,
type=click.Choice(["fish", "bash", "zsh", "powershell", "auto"]),
help="The shell type, default=auto",
)
@click.option(
"--path",
type=click.Path(file_okay=True, dir_okay=False, readable=True, resolve_path=True),
help="Custom installation path of the code to be evaluated by the shell. "
"The standard installation path is used by default.",
)
def completion_install(shell, path):

import click_completion # pylint: disable=import-outside-toplevel,import-error

shell = shell or click_completion.get_auto_shell()
path = path or get_completion_install_path(shell)
install_completion_code(shell, path)
click.echo(
"PlatformIO CLI completion has been installed for %s shell to %s \n"
"Please restart a current shell session."
% (click.style(shell, fg="cyan"), click.style(path, fg="blue"))
)


@completion.command("uninstall", short_help="Uninstall shell completion files/code")
@click.option(
"--shell",
default=None,
type=click.Choice(["fish", "bash", "zsh", "powershell", "auto"]),
help="The shell type, default=auto",
)
@click.option(
"--path",
type=click.Path(file_okay=True, dir_okay=False, readable=True, resolve_path=True),
help="Custom installation path of the code to be evaluated by the shell. "
"The standard installation path is used by default.",
)
def completion_uninstall(shell, path):

import click_completion # pylint: disable=import-outside-toplevel,import-error

shell = shell or click_completion.get_auto_shell()
path = path or get_completion_install_path(shell)
uninstall_completion_code(shell, path)
click.echo(
"PlatformIO CLI completion has been uninstalled for %s shell from %s \n"
"Please restart a current shell session."
% (click.style(shell, fg="cyan"), click.style(path, fg="blue"))
)
73 changes: 73 additions & 0 deletions platformio/commands/misc/completion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Copyright (c) 2014-present PlatformIO <[email protected]>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import subprocess

import click


def get_completion_install_path(shell):
home_dir = os.path.expanduser("~")
prog_name = click.get_current_context().find_root().info_name
if shell == "fish":
return os.path.join(
home_dir, ".config", "fish", "completions", "%s.fish" % prog_name
)
if shell == "bash":
return os.path.join(home_dir, ".bash_completion")
if shell == "zsh":
return os.path.join(home_dir, ".zshrc")
if shell == "powershell":
return subprocess.check_output(
["powershell", "-NoProfile", "echo $profile"]
).strip()
raise click.ClickException("%s is not supported." % shell)


def is_completion_code_installed(shell, path):
if shell == "fish" or not os.path.exists(path):
return False

import click_completion # pylint: disable=import-error,import-outside-toplevel

with open(path) as fp:
return click_completion.get_code(shell=shell) in fp.read()


def install_completion_code(shell, path):
import click_completion # pylint: disable=import-error,import-outside-toplevel

if is_completion_code_installed(shell, path):
return None

return click_completion.install(shell=shell, path=path)


def uninstall_completion_code(shell, path):
if not os.path.exists(path):
return True
if shell == "fish":
os.remove(path)
return True

import click_completion # pylint: disable=import-error,import-outside-toplevel

with open(path, "r+") as fp:
contents = fp.read()
fp.seek(0)
fp.truncate()
fp.write(contents.replace(click_completion.get_code(shell=shell), ""))

return True
2 changes: 1 addition & 1 deletion platformio/managers/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def build_contrib_pysite_deps(target_dir):

pythonexe = get_pythonexe_path()
for dep in get_contrib_pysite_deps():
subprocess.call(
subprocess.check_call(
[
pythonexe,
"-m",
Expand Down

0 comments on commit 01a1981

Please sign in to comment.