latch 2.51.2.dev6__tar.gz → 2.51.2.dev8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {latch-2.51.2.dev6/latch.egg-info → latch-2.51.2.dev8}/PKG-INFO +1 -1
- {latch-2.51.2.dev6 → latch-2.51.2.dev8/latch.egg-info}/PKG-INFO +1 -1
- latch-2.51.2.dev8/latch_cli/menus/common.py +35 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/menus/vt100.py +147 -11
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/menus/win32.py +177 -20
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/get_executions.py +43 -42
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/setup.py +2 -2
- latch-2.51.2.dev6/latch_cli/menus/common.py +0 -181
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/LICENSE +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/MANIFEST.in +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/README.md +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/account.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/executions.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/functions/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/functions/messages.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/functions/operators.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/functions/secrets.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/_transfer/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/_transfer/download.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/_transfer/manager.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/_transfer/node.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/_transfer/progress.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/_transfer/remote_copy.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/_transfer/throttle.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/_transfer/upload.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/_transfer/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/path.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/ldata/type.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/registry/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/registry/project.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/registry/record.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/registry/table.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/registry/types.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/registry/upstream_types/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/registry/upstream_types/types.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/registry/upstream_types/values.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/registry/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/resources/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/resources/conditional.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/resources/dynamic.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/resources/launch_plan.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/resources/map_tasks.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/resources/reference_workflow.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/resources/tasks.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/resources/workflow.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/types/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/types/directory.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/types/file.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/types/glob.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/types/json.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/types/metadata.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/types/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/verified/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/verified/deseq2.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/verified/mafft.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/verified/pathway.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/verified/rnaseq.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch/verified/trim_galore.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch.egg-info/SOURCES.txt +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch.egg-info/dependency_links.txt +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch.egg-info/entry_points.txt +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch.egg-info/requires.txt +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch.egg-info/top_level.txt +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/auth/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/auth/csrf.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/auth/oauth2.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/auth/pkce.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/auth/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/centromere/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/centromere/ctx.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/centromere/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/click_utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/constants.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/docker_utils/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/exceptions/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/exceptions/cache.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/exceptions/errors.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/exceptions/handler.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/exceptions/traceback.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/main.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/menus/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/menus/win32_types.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/nextflow/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/nextflow/config.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/nextflow/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/nextflow/workflow.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/cp/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/cp/autocomplete.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/cp/glob.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/cp/main.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/cp/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/execute/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/execute/main.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/execute/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/get.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/get_params.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/__pycache__/__init__.cpython-311.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/__pycache__/__init__.cpython-38.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/__pycache__/__init__.cpython-39.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/__pycache__/init.cpython-310.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/__pycache__/init.cpython-311.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/__pycache__/init.cpython-38.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/__pycache__/init.cpython-39.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/assemble_and_sort/.env +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/assemble_and_sort/LICENSE +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/assemble_and_sort/README.md +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/assemble_and_sort/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/assemble_and_sort/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/assemble_and_sort/assemble.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/assemble_and_sort/sort.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/assemble_and_sort/system-requirements.txt +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/common/.dockerignore +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_conda/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_conda/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_conda/conda_task.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_conda/environment.yaml +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_docker/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_docker/task.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_nf_integration/latch_metadata/__pycache__/__init__.cpython-311.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_nfcore/Dockerfile +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_nfcore/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_nfcore/task.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_r/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_r/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_r/environment.R +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_r/r_task.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_snakemake/.latch/latch_entrypoint +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_snakemake/Dockerfile +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_snakemake/Snakefile +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_snakemake/config.yaml +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_snakemake/environment.yaml +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_snakemake/latch_metadata.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_snakemake/scripts/plot-quals.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/example_snakemake/version +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/init.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/template/LICENSE +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/template/README.md +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/template/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/template/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/init/template/task.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/launch.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/local_dev.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/local_dev_old.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/login.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/ls.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/mkdir.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/move.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/preview.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/register/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/register/constants.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/register/register.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/register/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/rm.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/stop_pod.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/sync.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/test_data/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/test_data/ls.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/test_data/remove.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/test_data/upload.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/test_data/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/services/workspace.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/snakemake/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/snakemake/config/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/snakemake/config/parser.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/snakemake/config/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/snakemake/serialize.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/snakemake/serialize_utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/snakemake/single_task_snakemake.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/snakemake/utils.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/snakemake/workflow.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/tinyrequests.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/utils/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/utils/path.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/latch_cli/workflow_config.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/pyproject.toml +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/setup.cfg +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/tests/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/tests/cp/__init__.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/tests/fixtures.py +0 -0
- {latch-2.51.2.dev6 → latch-2.51.2.dev8}/tests/test_ls.py +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Callable, Generic, Tuple
|
|
3
|
+
|
|
4
|
+
from git import Optional
|
|
5
|
+
from typing_extensions import TypedDict, TypeVar
|
|
6
|
+
|
|
7
|
+
old_print = print
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def buffered_print() -> Tuple[Callable, Callable]:
|
|
11
|
+
buffer = []
|
|
12
|
+
|
|
13
|
+
def __print(*args):
|
|
14
|
+
for arg in args:
|
|
15
|
+
buffer.append(arg)
|
|
16
|
+
|
|
17
|
+
def __show():
|
|
18
|
+
nonlocal buffer
|
|
19
|
+
old_print("".join(buffer), flush=True, end="")
|
|
20
|
+
buffer = []
|
|
21
|
+
|
|
22
|
+
return __print, __show
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Allows for exactly one print per render, removing any weird flashing
|
|
26
|
+
# behavior and also speeding things up considerably
|
|
27
|
+
print, show = buffered_print()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
T = TypeVar("T")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SelectOption(TypedDict, Generic[T]):
|
|
34
|
+
display_name: str
|
|
35
|
+
value: T
|
|
@@ -3,7 +3,7 @@ import sys
|
|
|
3
3
|
import termios
|
|
4
4
|
import tty
|
|
5
5
|
from functools import wraps
|
|
6
|
-
from typing import Callable, List, Optional, TypeVar
|
|
6
|
+
from typing import Callable, List, Optional, Tuple, TypeVar
|
|
7
7
|
|
|
8
8
|
from typing_extensions import ParamSpec
|
|
9
9
|
|
|
@@ -15,6 +15,142 @@ P = ParamSpec("P")
|
|
|
15
15
|
T = TypeVar("T")
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
def clear(k: int):
|
|
19
|
+
"""
|
|
20
|
+
Clear `k` lines below the cursor, returning the cursor to the start of its original line
|
|
21
|
+
"""
|
|
22
|
+
print(f"\x1b[2K\x1b[1E" * (k) + f"\x1b[{k}F")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def draw_box(
|
|
26
|
+
ul_corner_pos: Tuple[int, int],
|
|
27
|
+
height: int,
|
|
28
|
+
width: int,
|
|
29
|
+
color: Optional[str] = None,
|
|
30
|
+
):
|
|
31
|
+
if height <= 0 or width <= 0:
|
|
32
|
+
return
|
|
33
|
+
move_cursor(ul_corner_pos)
|
|
34
|
+
draw_horizontal_line(width, make_corner=True, color=color)
|
|
35
|
+
draw_vertical_line(height, make_corner=True, color=color)
|
|
36
|
+
draw_horizontal_line(width, left=True, make_corner=True, color=color)
|
|
37
|
+
draw_vertical_line(height, up=True, make_corner=True, color=color)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def clear_screen():
|
|
41
|
+
print("\x1b[2J")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def remove_cursor():
|
|
45
|
+
print("\x1b[?25l")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def reveal_cursor():
|
|
49
|
+
print("\x1b[?25h")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def move_cursor(pos: Tuple[int, int]):
|
|
53
|
+
"""
|
|
54
|
+
Move the cursor to a given (x, y) coordinate
|
|
55
|
+
"""
|
|
56
|
+
x, y = pos
|
|
57
|
+
if x < 0 or y < 0:
|
|
58
|
+
return
|
|
59
|
+
print(f"\x1b[{y};{x}H")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def move_cursor_up(n: int):
|
|
63
|
+
if n <= 0:
|
|
64
|
+
return
|
|
65
|
+
print(f"\x1b[{n}A")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def line_up(n: int):
|
|
69
|
+
"""Moves to the start of the destination line"""
|
|
70
|
+
if n <= 0:
|
|
71
|
+
return
|
|
72
|
+
print(f"\x1b[{n}F")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def move_cursor_down(n: int):
|
|
76
|
+
if n <= 0:
|
|
77
|
+
return
|
|
78
|
+
print(f"\x1b[{n}B")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def line_down(n: int):
|
|
82
|
+
"""Moves to the start of the destination line"""
|
|
83
|
+
if n <= 0:
|
|
84
|
+
return
|
|
85
|
+
print(f"\x1b[{n}E")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def move_cursor_right(n: int):
|
|
89
|
+
if n <= 0:
|
|
90
|
+
return
|
|
91
|
+
print(f"\x1b[{n}C")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def move_cursor_left(n: int):
|
|
95
|
+
if n <= 0:
|
|
96
|
+
return
|
|
97
|
+
print(f"\x1b[{n}D")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def draw_vertical_line(
|
|
101
|
+
height: int,
|
|
102
|
+
up: bool = False,
|
|
103
|
+
make_corner: bool = False,
|
|
104
|
+
color: Optional[str] = None,
|
|
105
|
+
):
|
|
106
|
+
"""
|
|
107
|
+
Draws a vertical line with given `height`, going upwards if `up` is True
|
|
108
|
+
and downwards otherwise.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
if height <= 0:
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
if color is not None:
|
|
115
|
+
print(color)
|
|
116
|
+
sep = "\x1b[1A" if up else "\x1b[1B"
|
|
117
|
+
for i in range(height):
|
|
118
|
+
if i == 0 and make_corner:
|
|
119
|
+
corner = "\u2514" if up else "\u2510"
|
|
120
|
+
print(f"{corner}\x1b[1D{sep}")
|
|
121
|
+
else:
|
|
122
|
+
print(f"\u2502\x1b[1D{sep}")
|
|
123
|
+
if color is not None:
|
|
124
|
+
print("\x1b[0m")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def draw_horizontal_line(
|
|
128
|
+
width: int,
|
|
129
|
+
left: bool = False,
|
|
130
|
+
make_corner: bool = False,
|
|
131
|
+
color: Optional[str] = None,
|
|
132
|
+
):
|
|
133
|
+
"""
|
|
134
|
+
Draws a horizontal line with given `width`, going to the left if `left` is True
|
|
135
|
+
and to the right otherwise.
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
if width <= 0:
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
if color is not None:
|
|
142
|
+
print(color)
|
|
143
|
+
sep = "\x1b[2D" if left else ""
|
|
144
|
+
for i in range(width):
|
|
145
|
+
if i == 0 and make_corner:
|
|
146
|
+
corner = "\u2518" if left else "\u250c"
|
|
147
|
+
print(f"{corner}{sep}")
|
|
148
|
+
else:
|
|
149
|
+
print(f"\u2500{sep}")
|
|
150
|
+
if color is not None:
|
|
151
|
+
print("\x1b[0m")
|
|
152
|
+
|
|
153
|
+
|
|
18
154
|
def raw_input(f: Callable[P, T]) -> Callable[P, T]:
|
|
19
155
|
@wraps(f)
|
|
20
156
|
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
|
@@ -78,7 +214,7 @@ def select_tui(
|
|
|
78
214
|
curr_selected = 0
|
|
79
215
|
|
|
80
216
|
print(title)
|
|
81
|
-
|
|
217
|
+
line_down(2)
|
|
82
218
|
|
|
83
219
|
num_lines_rendered = 4 # 4 "extra" lines for header + footer
|
|
84
220
|
|
|
@@ -98,11 +234,11 @@ def select_tui(
|
|
|
98
234
|
print(f"{indent}{name}\x1b[1E")
|
|
99
235
|
num_lines_rendered += 1
|
|
100
236
|
|
|
101
|
-
|
|
237
|
+
line_down(1)
|
|
102
238
|
|
|
103
239
|
control_str = "[ARROW-KEYS] Navigate\t[ENTER] Select\t[Q] Quit"
|
|
104
240
|
print(control_str)
|
|
105
|
-
|
|
241
|
+
line_up(num_lines_rendered - 1)
|
|
106
242
|
|
|
107
243
|
common.show()
|
|
108
244
|
|
|
@@ -111,16 +247,16 @@ def select_tui(
|
|
|
111
247
|
curr_selected = 0
|
|
112
248
|
start_index = 0
|
|
113
249
|
_, term_height = os.get_terminal_size()
|
|
114
|
-
|
|
250
|
+
remove_cursor()
|
|
115
251
|
|
|
116
252
|
max_per_page = min(len(options), term_height - 4)
|
|
117
253
|
|
|
118
254
|
if clear_terminal:
|
|
119
|
-
|
|
120
|
-
|
|
255
|
+
clear_screen()
|
|
256
|
+
move_cursor((0, 0))
|
|
121
257
|
else:
|
|
122
258
|
print("\n" * (max_per_page + 3))
|
|
123
|
-
|
|
259
|
+
move_cursor_up(max_per_page + 4)
|
|
124
260
|
|
|
125
261
|
num_lines_rendered = render(
|
|
126
262
|
curr_selected,
|
|
@@ -151,7 +287,7 @@ def select_tui(
|
|
|
151
287
|
start_index += 1
|
|
152
288
|
else:
|
|
153
289
|
continue
|
|
154
|
-
|
|
290
|
+
clear(num_lines_rendered)
|
|
155
291
|
num_lines_rendered = render(
|
|
156
292
|
curr_selected,
|
|
157
293
|
start_index=start_index,
|
|
@@ -160,6 +296,6 @@ def select_tui(
|
|
|
160
296
|
except KeyboardInterrupt:
|
|
161
297
|
...
|
|
162
298
|
finally:
|
|
163
|
-
|
|
164
|
-
|
|
299
|
+
clear(num_lines_rendered)
|
|
300
|
+
reveal_cursor()
|
|
165
301
|
common.show()
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import msvcrt
|
|
2
2
|
import os
|
|
3
3
|
import sys
|
|
4
|
-
from ctypes import c_ulong, pointer, windll
|
|
4
|
+
from ctypes import byref, c_char, c_long, c_ulong, pointer, windll
|
|
5
5
|
from ctypes.wintypes import DWORD, HANDLE
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from enum import Enum
|
|
8
8
|
from functools import wraps
|
|
9
|
-
from typing import
|
|
9
|
+
from typing import Callable, List, Optional, Tuple, TypeVar
|
|
10
10
|
|
|
11
11
|
from typing_extensions import ParamSpec
|
|
12
12
|
|
|
@@ -14,19 +14,168 @@ from latch_cli.click_utils import AnsiCodes
|
|
|
14
14
|
|
|
15
15
|
from . import common
|
|
16
16
|
from .win32_types import (
|
|
17
|
+
CONSOLE_SCREEN_BUFFER_INFO,
|
|
18
|
+
COORD,
|
|
17
19
|
INPUT_RECORD,
|
|
18
20
|
KEY_EVENT_RECORD,
|
|
19
21
|
MOUSE_EVENT_RECORD,
|
|
20
22
|
STD_INPUT_HANDLE,
|
|
23
|
+
STD_OUTPUT_HANDLE,
|
|
21
24
|
EventTypes,
|
|
22
25
|
)
|
|
23
26
|
|
|
24
|
-
# assert sys.platform == "win32"
|
|
25
|
-
|
|
26
27
|
P = ParamSpec("P")
|
|
27
28
|
T = TypeVar("T")
|
|
28
29
|
|
|
29
30
|
|
|
31
|
+
hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# convenience dataclasses for readability
|
|
35
|
+
@dataclass
|
|
36
|
+
class Pair:
|
|
37
|
+
x: int
|
|
38
|
+
y: int
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class ConsoleScreenBufferInfo:
|
|
43
|
+
raw: CONSOLE_SCREEN_BUFFER_INFO
|
|
44
|
+
buffer_size: Pair
|
|
45
|
+
cursor_position: Pair
|
|
46
|
+
attributes: int
|
|
47
|
+
window_top_left: Pair
|
|
48
|
+
window_bottom_right: Pair
|
|
49
|
+
max_window_size: Pair
|
|
50
|
+
|
|
51
|
+
def window_dimensions(self) -> Pair:
|
|
52
|
+
return Pair(
|
|
53
|
+
x=self.window_bottom_right.x - self.window_top_left.x,
|
|
54
|
+
y=self.window_bottom_right.y - self.window_top_left.y,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_win32_screen_buffer_info() -> ConsoleScreenBufferInfo:
|
|
59
|
+
"""
|
|
60
|
+
https://github.com/prompt-toolkit/python-prompt-toolkit/blob/669541123c9a72da1fda662cbd0a18ffe9e6d113/src/prompt_toolkit/output/win32.py#L185
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
sbinfo = CONSOLE_SCREEN_BUFFER_INFO()
|
|
64
|
+
|
|
65
|
+
success = windll.kernel32.GetConsoleScreenBufferInfo(hconsole, byref(sbinfo))
|
|
66
|
+
|
|
67
|
+
if success:
|
|
68
|
+
return ConsoleScreenBufferInfo(
|
|
69
|
+
raw=sbinfo,
|
|
70
|
+
buffer_size=Pair(
|
|
71
|
+
x=sbinfo.dwSize.X,
|
|
72
|
+
y=sbinfo.dwSize.Y,
|
|
73
|
+
),
|
|
74
|
+
cursor_position=Pair(
|
|
75
|
+
x=sbinfo.dwCursorPosition.X,
|
|
76
|
+
y=sbinfo.dwCursorPosition.Y,
|
|
77
|
+
),
|
|
78
|
+
attributes=sbinfo.wAttributes,
|
|
79
|
+
window_top_left=Pair(
|
|
80
|
+
x=sbinfo.srWindow.Left,
|
|
81
|
+
y=sbinfo.srWindow.Top,
|
|
82
|
+
),
|
|
83
|
+
window_bottom_right=Pair(
|
|
84
|
+
x=sbinfo.srWindow.Right,
|
|
85
|
+
y=sbinfo.srWindow.Bottom,
|
|
86
|
+
),
|
|
87
|
+
max_window_size=Pair(
|
|
88
|
+
x=sbinfo.dwMaximumWindowSize.X,
|
|
89
|
+
y=sbinfo.dwMaximumWindowSize.Y,
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
else:
|
|
93
|
+
raise RuntimeError("No windows console found")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _erase(start: COORD, length: int) -> None:
|
|
97
|
+
"""
|
|
98
|
+
https://github.com/prompt-toolkit/python-prompt-toolkit/blob/669541123c9a72da1fda662cbd0a18ffe9e6d113/src/prompt_toolkit/output/win32.py#L255
|
|
99
|
+
"""
|
|
100
|
+
chars_written = c_ulong()
|
|
101
|
+
|
|
102
|
+
windll.kernel32.FillConsoleOutputCharacterA(
|
|
103
|
+
hconsole, c_char(b" "), DWORD(length), start, byref(chars_written)
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Reset attributes.
|
|
107
|
+
sbinfo = get_win32_screen_buffer_info()
|
|
108
|
+
windll.kernel32.FillConsoleOutputAttribute(
|
|
109
|
+
hconsole, sbinfo.attributes, length, start, byref(chars_written)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def clear(k: int):
|
|
114
|
+
"""
|
|
115
|
+
Clear `k` lines below the cursor, returning the cursor to the start of its original line
|
|
116
|
+
"""
|
|
117
|
+
sbinfo = get_win32_screen_buffer_info()
|
|
118
|
+
|
|
119
|
+
length = sbinfo.window_dimensions().x * k
|
|
120
|
+
_erase(sbinfo.raw.dwCursorPosition, length)
|
|
121
|
+
|
|
122
|
+
# does the cursor move at all here? do we need to move back to the original line?
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def clear_screen():
|
|
126
|
+
sbinfo = get_win32_screen_buffer_info()
|
|
127
|
+
dims = sbinfo.window_dimensions()
|
|
128
|
+
|
|
129
|
+
start = COORD(X=sbinfo.window_top_left.x, Y=sbinfo.window_top_left.y)
|
|
130
|
+
length = dims.x * dims.y
|
|
131
|
+
|
|
132
|
+
_erase(start, length)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def remove_cursor():
|
|
136
|
+
pass # not supported in windows afaict
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def reveal_cursor():
|
|
140
|
+
pass # not supported in windows afaict
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def move_cursor(x: int, y: int):
|
|
144
|
+
"""
|
|
145
|
+
Move the cursor to a given (x, y) coordinate
|
|
146
|
+
"""
|
|
147
|
+
if x < 0 or y < 0:
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
windll.kernel32.SetConsoleCursorPosition(hconsole, COORD(X=x, Y=y))
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def move_cursor_up(n: int):
|
|
154
|
+
if n <= 0:
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
sbinfo = get_win32_screen_buffer_info()
|
|
158
|
+
|
|
159
|
+
x = sbinfo.cursor_position.x
|
|
160
|
+
y = sbinfo.cursor_position.y - n
|
|
161
|
+
move_cursor(x, y)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def line_up(n: int):
|
|
165
|
+
"""Moves to the start of the destination line"""
|
|
166
|
+
sbinfo = get_win32_screen_buffer_info()
|
|
167
|
+
|
|
168
|
+
x = 0
|
|
169
|
+
y = sbinfo.cursor_position.y - n
|
|
170
|
+
move_cursor(x, y)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def line_down(n: int):
|
|
174
|
+
"""Moves to the start of the destination line"""
|
|
175
|
+
|
|
176
|
+
line_up(-n)
|
|
177
|
+
|
|
178
|
+
|
|
30
179
|
def raw_input(f: Callable[P, T]) -> Callable[P, T]:
|
|
31
180
|
# ayush: got most of this from
|
|
32
181
|
# https://github.com/prompt-toolkit/python-prompt-toolkit/blob/669541123c9a72da1fda662cbd0a18ffe9e6d113/src/prompt_toolkit/input/win32.py
|
|
@@ -153,7 +302,7 @@ def select_tui(
|
|
|
153
302
|
curr_selected = 0
|
|
154
303
|
|
|
155
304
|
print(title)
|
|
156
|
-
|
|
305
|
+
line_down(2)
|
|
157
306
|
|
|
158
307
|
num_lines_rendered = 4 # 4 "extra" lines for header + footer
|
|
159
308
|
|
|
@@ -162,22 +311,30 @@ def select_tui(
|
|
|
162
311
|
break
|
|
163
312
|
name = options[i]["display_name"]
|
|
164
313
|
if i == curr_selected:
|
|
165
|
-
color = AnsiCodes.color
|
|
166
|
-
bold = AnsiCodes.bold
|
|
167
|
-
reset = AnsiCodes.full_reset
|
|
168
|
-
|
|
169
314
|
prefix = indent[:-2] + "> "
|
|
170
315
|
|
|
171
|
-
|
|
316
|
+
sbinfo = get_win32_screen_buffer_info()
|
|
317
|
+
attrs = sbinfo.attributes
|
|
318
|
+
|
|
319
|
+
# light blue
|
|
320
|
+
color = 0x9
|
|
321
|
+
attrs = attrs & ~0xF
|
|
322
|
+
attrs |= color
|
|
323
|
+
|
|
324
|
+
attrs |= 1 << 8 # bold
|
|
325
|
+
|
|
326
|
+
windll.kernel32.SetConsoleTextAttribute(hconsole, attrs)
|
|
327
|
+
print(f"{prefix}{name}\n")
|
|
328
|
+
windll.kernel32.SetConsoleTextAttribute(hconsole, sbinfo.attributes)
|
|
172
329
|
else:
|
|
173
|
-
print(f"{indent}{name}\
|
|
330
|
+
print(f"{indent}{name}\n")
|
|
174
331
|
num_lines_rendered += 1
|
|
175
332
|
|
|
176
|
-
|
|
333
|
+
line_down(1)
|
|
177
334
|
|
|
178
335
|
control_str = "[ARROW-KEYS] Navigate\t[ENTER] Select\t[Q] Quit"
|
|
179
336
|
print(control_str)
|
|
180
|
-
|
|
337
|
+
line_up(num_lines_rendered - 1)
|
|
181
338
|
|
|
182
339
|
common.show()
|
|
183
340
|
|
|
@@ -186,16 +343,16 @@ def select_tui(
|
|
|
186
343
|
curr_selected = 0
|
|
187
344
|
start_index = 0
|
|
188
345
|
_, term_height = os.get_terminal_size()
|
|
189
|
-
|
|
346
|
+
remove_cursor()
|
|
190
347
|
|
|
191
348
|
max_per_page = min(len(options), term_height - 4)
|
|
192
349
|
|
|
193
350
|
if clear_terminal:
|
|
194
|
-
|
|
195
|
-
|
|
351
|
+
clear_screen()
|
|
352
|
+
move_cursor(0, 0)
|
|
196
353
|
else:
|
|
197
354
|
print("\n" * (max_per_page + 3))
|
|
198
|
-
|
|
355
|
+
move_cursor_up(max_per_page + 4)
|
|
199
356
|
|
|
200
357
|
num_lines_rendered = render(
|
|
201
358
|
curr_selected,
|
|
@@ -227,7 +384,7 @@ def select_tui(
|
|
|
227
384
|
else:
|
|
228
385
|
continue
|
|
229
386
|
|
|
230
|
-
|
|
387
|
+
clear(num_lines_rendered)
|
|
231
388
|
num_lines_rendered = render(
|
|
232
389
|
curr_selected,
|
|
233
390
|
start_index=start_index,
|
|
@@ -236,6 +393,6 @@ def select_tui(
|
|
|
236
393
|
except KeyboardInterrupt:
|
|
237
394
|
...
|
|
238
395
|
finally:
|
|
239
|
-
|
|
240
|
-
|
|
396
|
+
clear(num_lines_rendered)
|
|
397
|
+
reveal_cursor()
|
|
241
398
|
common.show()
|