update vsext workflow

This commit is contained in:
Daylin Morgan 2023-09-27 01:37:54 -05:00
parent 3f302c5ef3
commit 5a0b9f0457
Signed by: daylin
GPG key ID: C1E52E7DD81DF79F
5 changed files with 215 additions and 267 deletions

View file

@ -0,0 +1,155 @@
#!/usr/bin/env -S viv run rich 'git+https://github.com/usu-dev/usu-py.git' -s
import argparse
import shlex
import subprocess
import sys
from pathlib import Path
import usu
from rich.align import Align
from rich.columns import Columns
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Confirm
from rich.table import Table
console = Console()
def run(cmd, capture=True, returncode=False):
result = subprocess.run(
shlex.split(cmd),
stdout=subprocess.PIPE if capture else None,
text=True,
shell=False,
)
if returncode:
return result.returncode
elif capture:
return result.stdout.strip()
def parse_exts(usu_file):
exts = usu.loads(Path(usu_file).read_text())
all = [v for ext_list in exts.values() for v in ext_list]
return exts, sorted(all)
class SubcommandHelpFormatter(argparse.RawDescriptionHelpFormatter):
def _format_action(self, action):
parts = super(argparse.RawDescriptionHelpFormatter, self)._format_action(action)
if action.nargs == argparse.PARSER:
parts = "\n".join(parts.split("\n")[1:])
return parts
def get_args():
p = argparse.ArgumentParser(formatter_class=SubcommandHelpFormatter)
sp = p.add_subparsers(title="commands", metavar="", dest="command", required=True)
check = sp.add_parser(
"check",
help="check the extensions which have already been installed",
aliases=["c"],
)
check.add_argument("--verbose", help="show more information", action="store_true")
install = sp.add_parser(
"install", help="install the extensions from the spec", aliases=["i"]
)
install.add_argument(
"-f", "--force", help="force the installation of exts", action="store_true"
)
sp.add_parser("remove", help="remove all extra packages", aliases=["r"])
p.add_argument(
"-s",
"--spec",
help="mardown spec list (default ./exts.usu)",
default=Path.cwd() / "exts.usu",
)
if len(sys.argv) < 2:
p.print_help()
sys.exit(1)
return p.parse_args()
def get_extra_exts(spec, installed):
# sanitize lists
spec = [ext.lower() for ext in spec]
installed = [ext.lower() for ext in installed]
return [ext for ext in spec if ext not in installed], [
ext for ext in installed if ext not in spec
]
def code(flag, exts, force=False):
cmd = "code " + " ".join([f"{flag} {ext}" for ext in exts])
if force:
cmd += " --force"
run(cmd, capture=False)
def header():
console.print(
Panel(
Align("[yellow]VS Code Extensions Installer", align="center"),
style="magenta",
)
)
def installed_table(head, exts, not_installed):
table = Table(title=head)
table.add_column("extension")
table.add_column("installed?")
for ext in exts:
installed = ext.lower() not in not_installed
table.add_row(
ext, "Y" if installed else "N", style = 'green' if installed else "red"
)
return table
def main():
args = get_args()
header()
spec_sections, spec_list = parse_exts(args.spec)
not_installed, extra_installed = get_extra_exts(
spec_list, run("code --list-extensions").splitlines()
)
if args.command == "check" or args.command == "c":
tables = (
installed_table(head, exts, not_installed)
for head, exts in spec_sections.items()
)
console.print(Columns(tables))
if not_installed:
console.print(f"[yellow]missing {len(not_installed)} extensions")
if extra_installed:
console.print(f"[red]{len(extra_installed)} extra extensions installed")
if not args.verbose:
console.print("[dim]run with --verbose to see extra extensions")
else:
console.print(Columns(extra_installed))
elif args.command == "install" or args.command == "i":
console.print("[bold]Installing extensions from spec list")
code("--install-extension", spec_list, args.force)
elif args.command == "remove" or args.command == "r":
console.print("[red]Removing unspecified extensions")
console.print(Columns(extra_installed))
if Confirm.ask(f"Remove the above {len(extra_installed)} packages?"):
code("--uninstall-extension", extra_installed)
if __name__ == "__main__":
main()

59
home/dot_vscode/exts.usu Normal file
View file

@ -0,0 +1,59 @@
# VS Code Extensions
:general [
ms-vscode-remote.remote-ssh
ms-vscode-remote.remote-ssh-edit
ms-azuretools.vscode-docker
ms-vscode-remote.remote-containers
ms-vscode.remote-repositories
vscodevim.vim
]
:misc-tools [
janisdd.vscode-edit-csv
naumovs.color-highlight
davidhouchin.whitespace-plus
antfu.slidev
antfu.file-nesting
mhutchie.git-graph
]
:web-dev [
ritwickdey.liveserver
esbenp.prettier-vscode
astro-build.astro-vscode
]
:ui [
johnpapa.vscode-peacock
PKief.material-icon-theme
catppuccin.catppuccin-vsc
catppuccin.catppuccin-vsc-icons
]
:editing [
metaseed.metajump
christian-kohler.path-intellisense
aaron-bond.better-comments
streetsidesoftware.code-spell-checker
]
:python [
ms-python.python
ms-toolsai.jupyter
quarto.quarto
charliermarsh.ruff
]
:languages [
golang.go
bbenoist.nix
antfu.unocss
budparr.language-hugo-vscode
snakemake.snakemake-lang
eww-yuck.yuck
tamasfe.even-better-toml
dlasagno.rasi
nimsaem.nimvscode
]

View file

@ -3,4 +3,4 @@
<!-- i.e. something like chezmoi forget --interactive ~/$(chezmoi managed | fzf) -->
- [ ] make a command to 'forget' files using fzf as selector
- [ ] deal with the abomination that is the ./vscode directory
- [x] deal with the abomination that is the ./vscode directory

View file

@ -1,60 +0,0 @@
# VS Code Extensions
## general
ms-vscode-remote.remote-ssh
ms-vscode-remote.remote-ssh-edit
ms-vscode-remote.remote-wsl
ms-azuretools.vscode-docker
ms-vscode-remote.remote-containers
ms-vscode.remote-repositories
vscodevim.vim
## misc-tools
Shan.code-settings-sync
janisdd.vscode-edit-csv
naumovs.color-highlight
davidhouchin.whitespace-plus
dlasagno.rasi
antfu.slidev
antfu.file-nesting
## web-dev
bradlc.vscode-tailwindcss
ritwickdey.liveserver
esbenp.prettier-vscode
antfu.unocss
astro-build.astro-vscode
## styling
johnpapa.vscode-peacock
PKief.material-icon-theme
Thomaz.preparing
catppuccin.catppuccin-vsc
## code-help
metaseed.metajump
christian-kohler.path-intellisense
aaron-bond.better-comments
streetsidesoftware.code-spell-checker
eamodio.gitlens
vsls-contrib.gistfs
mhutchie.git-graph
## python
ms-python.python
ms-python.flake8
ms-toolsai.jupyter
ms-python.vscode-pylance
ms-toolsai.jupyter-keymap
ms-toolsai.jupyter-renderers
njpwerner.autodocstring
quarto.quarto
## language-support
budparr.language-hugo-vscode
skellock.just
snakemake.snakemake-lang
voorjaar.windicss-intellisense
eww-yuck.yuck
bungcip.better-toml

View file

@ -1,206 +0,0 @@
#!/usr/bin/env python3
import argparse
import shlex
import subprocess
import sys
from pathlib import Path
from shutil import which
def is_tool(name):
"""Check whether `name` is on PATH and marked as executable."""
if not which(name):
print(f"ERROR: {name} is not found in your PATH")
sys.exit(1)
def run(cmd, capture=True, returncode=False):
result = subprocess.run(
shlex.split(cmd),
stdout=subprocess.PIPE if capture else None,
text=True,
shell=False,
)
if returncode:
return result.returncode
elif capture:
return result.stdout.strip()
class Gum:
def __init__(self):
is_tool("gum")
def confirm(self, question):
return not run(
"gum confirm "
"--selected.bold "
"--selected.background 11 "
"--selected.foreground 8 "
f"'{question}'",
returncode=True,
)
def color(self, text, color):
return run(f'gum style --foreground {color} "{text}"')
def header(self, text, color=11):
run(
"gum style "
"--foreground 212 --border-foreground 212 --border rounded "
'--align center --width 30 --margin "1 4" '
f"'{self.color(text,color)}'",
capture=False,
)
def choose(self, options):
if isinstance(options, str):
options = options.split("")
if isinstance(options, list):
options = "".join([f"'{i}'" for i in options])
return run(f"gum choose {options}")
def input(self, placeholder, value):
run(
"gum input" + f"--placeholder {placeholder}"
if placeholder
else "" + f"--value {value}"
if value
else ""
)
def spinner(self, placeholder, cmd):
run(f"gum spin -s points --title '{placeholder}'" + cmd)
gum = Gum()
def pprint(text, color):
print(gum.color(text, color))
def parse_exts(mdfile):
with Path(mdfile).open("r") as f:
md = f.read()
md = md.split("##")[1:]
exts = {}
all = []
for section in md:
head = section.splitlines()[0].strip()
exts[head] = []
for line in section.splitlines()[1:]:
if line == "":
continue
exts[head].append(line.strip())
all.append(line.strip())
return exts, sorted(all)
class SubcommandHelpFormatter(argparse.RawDescriptionHelpFormatter):
def _format_action(self, action):
parts = super(argparse.RawDescriptionHelpFormatter, self)._format_action(action)
if action.nargs == argparse.PARSER:
parts = "\n".join(parts.split("\n")[1:])
return parts
def get_args():
p = argparse.ArgumentParser(formatter_class=SubcommandHelpFormatter)
sp = p.add_subparsers(title="commands", metavar="", dest="command",required=True)
check = sp.add_parser(
"check",
help="check the extensions which have already been installed",
aliases = ['c']
)
install = sp.add_parser(
"install",
help="install the extensions from the spec",
aliases =['i']
)
install.add_argument(
"-f", "--force", help="force the installation of exts", action="store_true"
)
remove = sp.add_parser(
"remove",
help="remove all extra packages",
aliases = ['r']
)
p.add_argument(
"-s",
"--spec",
help="mardown spec list (default ~/.dotfiles/vscode/spec.md)",
default=Path.home() / ".dotfiles" / "vscode" / "spec.md",
)
if len(sys.argv) < 2:
# p.print_usage()
p.print_help()
sys.exit(1)
return p.parse_args()
def get_extra_exts(spec, installed):
# sanitize lists
spec = [ext.lower() for ext in spec]
installed = [ext.lower() for ext in installed]
return [ext for ext in spec if ext not in installed], [
ext for ext in installed if ext not in spec
]
def code(flag, exts, force=False):
cmd = "code " + " ".join([f"{flag} {ext}" for ext in exts])
if force:
cmd +=" --force"
run(cmd, capture=False)
def main():
args = get_args()
gum.header("VS Code Extensions Installer")
spec_sections, spec_list = parse_exts(args.spec)
not_installed, extra_installed = get_extra_exts(
spec_list, run("code --list-extensions").splitlines()
)
if args.command == "check" or args.command == "c":
for head, exts in spec_sections.items():
pprint(f"## {head}", 11)
for ext in exts:
if ext.lower() in not_installed:
pprint(ext, 9)
else:
print(ext)
if extra_installed:
pprint("\nExtra installed extensions:", 11)
print("\n".join(extra_installed))
elif args.command == "install" or args.command =='i':
pprint("Installing extensions from spec list", 11)
code("--install-extension", spec_list, args.force)
elif args.command == "remove" or args.command == "r":
pprint("Removing extensions I don't know about", 11)
print("\n".join(extra_installed) + "\n")
if gum.confirm(f"Remove the above {len(extra_installed)} packages"):
print("bye bye packages")
code("--uninstall-extension", extra_installed)
if __name__ == "__main__":
main()