diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c6b3e8ce9..0c5f3acee 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,5 @@ # Plugin owners plugins/archlinux/ @ratijas -plugins/aws/ @maksyms plugins/genpass/ @atoponce plugins/git-lfs/ @hellovietduc plugins/gitfast/ @felipec @@ -10,3 +9,5 @@ plugins/shell-proxy/ @septs plugins/universalarchive/ @Konfekt plugins/wp-cli/ @joshmedeski plugins/zoxide/ @ajeetdsouza +plugins/starship/ @axieax +plugins/dbt/ @msempere diff --git a/.github/dependencies.yml b/.github/dependencies.yml new file mode 100644 index 000000000..6d138736c --- /dev/null +++ b/.github/dependencies.yml @@ -0,0 +1,20 @@ +dependencies: + plugins/gitfast: + repo: felipec/git-completion + branch: master + version: tag:v2.0 + postcopy: | + set -e + rm -rf git-completion.plugin.zsh Makefile README.adoc t tools + test -e git-completion.zsh && mv -f git-completion.zsh _git + plugins/z: + branch: master + repo: agkozak/zsh-z + version: afaf2965b41fdc6ca66066e09382726aa0b6aa04 + precopy: | + set -e + test -e README.md && mv -f README.md MANUAL.md + postcopy: | + set -e + test -e _zshz && mv -f _zshz _z + test -e zsh-z.plugin.zsh && mv -f zsh-z.plugin.zsh z.plugin.zsh diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml new file mode 100644 index 000000000..2e2217e1c --- /dev/null +++ b/.github/workflows/dependencies.yml @@ -0,0 +1,29 @@ +name: Update dependencies +on: + workflow_dispatch: {} + # schedule: + # - cron: '34 3 * * */8' + +jobs: + check: + name: Check for updates + runs-on: ubuntu-latest + if: github.repository == 'ohmyzsh/ohmyzsh' + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Authenticate as @ohmyzsh + id: generate_token + uses: ohmyzsh/github-app-token@v2 + with: + app_id: ${{ secrets.OHMYZSH_APP_ID }} + private_key: ${{ secrets.OHMYZSH_APP_PRIVATE_KEY }} + - name: Process dependencies + env: + GH_TOKEN: ${{ steps.generate_token.outputs.token }} + GIT_APP_NAME: ohmyzsh[bot] + GIT_APP_EMAIL: 54982679+ohmyzsh[bot]@users.noreply.github.com + TMP_DIR: ${{ runner.temp }} + run: | + pip install -r .github/workflows/dependencies/requirements.txt + python3 .github/workflows/dependencies/updater.py diff --git a/.github/workflows/dependencies/requirements.txt b/.github/workflows/dependencies/requirements.txt new file mode 100644 index 000000000..3c4c149ea --- /dev/null +++ b/.github/workflows/dependencies/requirements.txt @@ -0,0 +1,2 @@ +PyYAML~=6.0.1 +requests~=2.31.0 diff --git a/.github/workflows/dependencies/updater.py b/.github/workflows/dependencies/updater.py new file mode 100644 index 000000000..f54d316f9 --- /dev/null +++ b/.github/workflows/dependencies/updater.py @@ -0,0 +1,450 @@ +import os +import subprocess +import sys +import requests +import shutil +import yaml +from copy import deepcopy +from typing import Optional, TypedDict + +# Get TMP_DIR variable from environment +TMP_DIR = os.path.join(os.environ.get("TMP_DIR", "/tmp"), "ohmyzsh") +# Relative path to dependencies.yml file +DEPS_YAML_FILE = ".github/dependencies.yml" +# Dry run flag +DRY_RUN = os.environ.get("DRY_RUN", "0") == "1" + +import timeit +class CodeTimer: + def __init__(self, name=None): + self.name = " '" + name + "'" if name else '' + + def __enter__(self): + self.start = timeit.default_timer() + + def __exit__(self, exc_type, exc_value, traceback): + self.took = (timeit.default_timer() - self.start) * 1000.0 + print('Code block' + self.name + ' took: ' + str(self.took) + ' ms') + + +### YAML representation +def str_presenter(dumper, data): + """ + Configures yaml for dumping multiline strings + Ref: https://stackoverflow.com/a/33300001 + """ + if len(data.splitlines()) > 1: # check for multiline string + return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') + return dumper.represent_scalar('tag:yaml.org,2002:str', data) + +yaml.add_representer(str, str_presenter) +yaml.representer.SafeRepresenter.add_representer(str, str_presenter) + + +# Types +class DependencyDict(TypedDict): + repo: str + branch: str + version: str + precopy: Optional[str] + postcopy: Optional[str] + +class DependencyYAML(TypedDict): + dependencies: dict[str, DependencyDict] + +class UpdateStatus(TypedDict): + has_updates: bool + version: Optional[str] + compare_url: Optional[str] + head_ref: Optional[str] + head_url: Optional[str] + + +class CommandRunner: + class Exception(Exception): + def __init__(self, message, returncode, stage, stdout, stderr): + super().__init__(message) + self.returncode = returncode + self.stage = stage + self.stdout = stdout + self.stderr = stderr + + @staticmethod + def run_or_fail(command: list[str], stage: str, *args, **kwargs): + if DRY_RUN and command[0] == "gh": + command.insert(0, "echo") + + result = subprocess.run(command, *args, capture_output=True, **kwargs) + + if result.returncode != 0: + raise CommandRunner.Exception( + f"{stage} command failed with exit code {result.returncode}", returncode=result.returncode, + stage=stage, + stdout=result.stdout.decode("utf-8"), + stderr=result.stderr.decode("utf-8") + ) + + return result + + +class DependencyStore: + store: DependencyYAML = { + "dependencies": {} + } + + @staticmethod + def set(data: DependencyYAML): + DependencyStore.store = data + + @staticmethod + def update_dependency_version(path: str, version: str) -> DependencyYAML: + with CodeTimer(f"store deepcopy: {path}"): + store_copy = deepcopy(DependencyStore.store) + + dependency = store_copy["dependencies"].get(path, {}) + dependency["version"] = version + store_copy["dependencies"][path] = dependency + + return store_copy + + @staticmethod + def write_store(file: str, data: DependencyYAML): + with open(file, "w") as yaml_file: + yaml.safe_dump(data, yaml_file, sort_keys=False) + + +class Dependency: + def __init__(self, path: str, values: DependencyDict): + self.path = path + self.values = values + + self.name: str = "" + self.desc: str = "" + self.kind: str = "" + + match path.split("/"): + case ["plugins", name]: + self.name = name + self.kind = "plugin" + self.desc = f"{name} plugin" + case ["themes", name]: + self.name = name.replace(".zsh-theme", "") + self.kind = "theme" + self.desc = f"{self.name} theme" + case _: + self.name = self.desc = path + + def __str__(self): + output: str = "" + for key in DependencyDict.__dict__['__annotations__'].keys(): + if key not in self.values: + output += f"{key}: None\n" + continue + + value = self.values[key] + if "\n" not in value: + output += f"{key}: {value}\n" + else: + output += f"{key}:\n " + output += value.replace("\n", "\n ", value.count("\n") - 1) + return output + + def update_or_notify(self): + # Print dependency settings + print(f"Processing {self.desc}...", file=sys.stderr) + print(self, file=sys.stderr) + + # Check for updates + repo = self.values["repo"] + remote_branch = self.values["branch"] + version = self.values["version"] + is_tag = version.startswith("tag:") + + try: + with CodeTimer(f"update check: {repo}"): + if is_tag: + status = GitHub.check_newer_tag(repo, version.replace("tag:", "")) + else: + status = GitHub.check_updates(repo, remote_branch, version) + + if status["has_updates"]: + short_sha = status["head_ref"][:8] + new_version = status["version"] if is_tag else short_sha + + try: + # Create new branch + branch = Git.create_branch(self.path, new_version) + + # Update dependencies.yml file + self.__update_yaml(f"tag:{new_version}" if is_tag else status["version"]) + + # Update dependency files + self.__apply_upstream_changes() + + # Add all changes and commit + Git.add_and_commit(self.name, short_sha) + + # Push changes to remote + Git.push(branch) + + # Create GitHub PR + GitHub.create_pr( + branch, + f"feat({self.name}): update to version {new_version}", + f"""## Description + +Update for **{self.desc}**: update to version [{new_version}]({status['head_url']}). +Check out the [list of changes]({status['compare_url']}). +""" + ) + + # Clean up repository + Git.clean_repo() + except (CommandRunner.Exception, shutil.Error) as e: + # Handle exception on automatic update + match type(e): + case CommandRunner.Exception: + # Print error message + print(f"Error running {e.stage} command: {e.returncode}", file=sys.stderr) + print(e.stderr, file=sys.stderr) + case shutil.Error: + print(f"Error copying files: {e}", file=sys.stderr) + + try: + Git.clean_repo() + except CommandRunner.Exception as e: + print(f"Error reverting repository to clean state: {e}", file=sys.stderr) + sys.exit(1) + + # Create a GitHub issue to notify maintainer + title = f"{self.path}: update to {new_version}" + body = ( + f"""## Description + +There is a new version of `{self.name}` {self.kind} available. + +New version: [{new_version}]({status['head_url']}) +Check out the [list of changes]({status['compare_url']}). +""" + ) + + print(f"Creating GitHub issue", file=sys.stderr) + print(f"{title}\n\n{body}", file=sys.stderr) + GitHub.create_issue(title, body) + except Exception as e: + print(e, file=sys.stderr) + + def __update_yaml(self, new_version: str) -> None: + dep_yaml = DependencyStore.update_dependency_version(self.path, new_version) + DependencyStore.write_store(DEPS_YAML_FILE, dep_yaml) + + def __apply_upstream_changes(self) -> None: + # Patterns to ignore in copying files from upstream repo + GLOBAL_IGNORE = [ + ".git", + ".github", + ".gitignore" + ] + + path = os.path.abspath(self.path) + precopy = self.values.get("precopy") + postcopy = self.values.get("postcopy") + + repo = self.values["repo"] + branch = self.values["branch"] + remote_url = f"https://github.com/{repo}.git" + repo_dir = os.path.join(TMP_DIR, repo) + + # Clone repository + Git.clone(remote_url, branch, repo_dir, reclone=True) + + # Run precopy on tmp repo + if precopy is not None: + print("Running precopy script:", end="\n ", file=sys.stderr) + print(precopy.replace("\n", "\n ", precopy.count("\n") - 1), file=sys.stderr) + CommandRunner.run_or_fail(["bash", "-c", precopy], cwd=repo_dir, stage="Precopy") + + # Copy files from upstream repo + print(f"Copying files from {repo_dir} to {path}", file=sys.stderr) + shutil.copytree(repo_dir, path, dirs_exist_ok=True, ignore=shutil.ignore_patterns(*GLOBAL_IGNORE)) + + # Run postcopy on our repository + if postcopy is not None: + print("Running postcopy script:", end="\n ", file=sys.stderr) + print(postcopy.replace("\n", "\n ", postcopy.count("\n") - 1), file=sys.stderr) + CommandRunner.run_or_fail(["bash", "-c", postcopy], cwd=path, stage="Postcopy") + + +class Git: + default_branch = "master" + + @staticmethod + def clone(remote_url: str, branch: str, repo_dir: str, reclone=False): + # If repo needs to be fresh + if reclone and os.path.exists(repo_dir): + shutil.rmtree(repo_dir) + + # Clone repo in tmp directory and checkout branch + if not os.path.exists(repo_dir): + print(f"Cloning {remote_url} to {repo_dir} and checking out {branch}", file=sys.stderr) + CommandRunner.run_or_fail(["git", "clone", "--depth=1", "-b", branch, remote_url, repo_dir], stage="Clone") + + @staticmethod + def create_branch(path: str, version: str): + # Get current branch name + result = CommandRunner.run_or_fail(["git", "rev-parse", "--abbrev-ref", "HEAD"], stage="GetDefaultBranch") + Git.default_branch = result.stdout.decode("utf-8").strip() + + # Create new branch and return created branch name + branch_name = f"update/{path}/{version}" + CommandRunner.run_or_fail(["git", "checkout", "-b", branch_name], stage="CreateBranch") + return branch_name + + @staticmethod + def add_and_commit(scope: str, version: str): + user_name = os.environ.get("GIT_APP_NAME") + user_email = os.environ.get("GIT_APP_EMAIL") + + # Add all files to git staging + CommandRunner.run_or_fail(["git", "add", "-A", "-v"], stage="AddFiles") + + # Reset environment and git config + clean_env = os.environ.copy() + clean_env["LANG"]="C.UTF-8" + clean_env["GIT_CONFIG_GLOBAL"]="/dev/null" + clean_env["GIT_CONFIG_NOSYSTEM"]="1" + + # Commit with settings above + CommandRunner.run_or_fail([ + "git", + "-c", f"user.name={user_name}", + "-c", f"user.email={user_email}", + "commit", + "-m", f"feat({scope}): update to {version}" + ], stage="CreateCommit", env=clean_env) + + @staticmethod + def push(branch: str): + CommandRunner.run_or_fail(["git", "push", "-u", "origin", branch], stage="PushBranch") + + @staticmethod + def clean_repo(): + CommandRunner.run_or_fail(["git", "reset", "--hard", "HEAD"], stage="ResetRepository") + CommandRunner.run_or_fail(["git", "checkout", Git.default_branch], stage="CheckoutDefaultBranch") + + +class GitHub: + @staticmethod + def check_newer_tag(repo, current_tag) -> UpdateStatus: + # GET /repos/:owner/:repo/git/refs/tags + url = f"https://api.github.com/repos/{repo}/git/refs/tags" + + # Send a GET request to the GitHub API + response = requests.get(url) + + # If the request was successful + if response.status_code == 200: + # Parse the JSON response + data = response.json() + + if len(data) == 0: + return { + "has_updates": False, + } + + latest_ref = data[-1] + latest_tag = latest_ref["ref"].replace("refs/tags/", "") + + if latest_tag == current_tag: + return { + "has_updates": False, + } + + return { + "has_updates": True, + "version": latest_tag, + "compare_url": f"https://github.com/{repo}/compare/{current_tag}...{latest_tag}", + "head_ref": latest_ref["object"]["sha"], + "head_url": f"https://github.com/{repo}/releases/tag/{latest_tag}", + } + else: + # If the request was not successful, raise an exception + raise Exception(f"GitHub API request failed with status code {response.status_code}: {response.json()}") + + @staticmethod + def check_updates(repo, branch, version) -> UpdateStatus: + # TODO: add support for semver updating (based on tags) + # Check if upstream github repo has a new version + # GitHub API URL for comparing two commits + url = f"https://api.github.com/repos/{repo}/compare/{version}...{branch}" + + # Send a GET request to the GitHub API + response = requests.get(url) + + # If the request was successful + if response.status_code == 200: + # Parse the JSON response + data = response.json() + + # If the base is behind the head, there is a newer version + has_updates = data["status"] != "identical" + + if not has_updates: + return { + "has_updates": False, + } + + return { + "has_updates": data["status"] != "identical", + "version": data["commits"][-1]["sha"], + "compare_url": data["permalink_url"], + "head_ref": data["commits"][-1]["sha"], + "head_url": data["commits"][-1]["html_url"] + } + else: + # If the request was not successful, raise an exception + raise Exception(f"GitHub API request failed with status code {response.status_code}: {response.json()}") + + @staticmethod + def create_issue(title: str, body: str) -> None: + cmd = [ + "gh", + "issue", + "create", + "-t", title, + "-b", body + ] + CommandRunner.run_or_fail(cmd, stage="CreateIssue") + + @staticmethod + def create_pr(branch: str, title: str, body: str) -> None: + cmd = [ + "gh", + "pr", + "create", + "-B", Git.default_branch, + "-H", branch, + "-t", title, + "-b", body + ] + CommandRunner.run_or_fail(cmd, stage="CreatePullRequest") + + +def main(): + # Load the YAML file + with open(DEPS_YAML_FILE, "r") as yaml_file: + data: DependencyYAML = yaml.safe_load(yaml_file) + + if "dependencies" not in data: + raise Exception(f"dependencies.yml not properly formatted") + + # Cache YAML version + DependencyStore.set(data) + + dependencies = data["dependencies"] + for path in dependencies: + dependency = Dependency(path, dependencies[path]) + dependency.update_or_notify() + +if __name__ == "__main__": + main() diff --git a/.github/workflows/installer.yml b/.github/workflows/installer.yml new file mode 100644 index 000000000..cad5d445b --- /dev/null +++ b/.github/workflows/installer.yml @@ -0,0 +1,56 @@ +name: Test and Deploy installer +on: + workflow_dispatch: {} + push: + paths: + - 'tools/install.sh' + - '.github/workflows/installer/**' + - '.github/workflows/installer.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: false + +permissions: + contents: read # to checkout + +jobs: + test: + name: Test installer + if: github.repository == 'ohmyzsh/ohmyzsh' + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - ubuntu-latest + - macos-latest + steps: + - name: Set up git repository + uses: actions/checkout@v3 + - name: Install zsh + if: runner.os == 'Linux' + run: sudo apt-get update; sudo apt-get install zsh + - name: Test installer + run: sh ./tools/install.sh + + deploy: + name: Deploy installer in install.ohmyz.sh + if: github.ref == 'refs/heads/master' + runs-on: ubuntu-latest + environment: vercel + needs: + - test + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Install Vercel CLI + run: npm install -g vercel + - name: Setup project and deploy + env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + run: | + cp tools/install.sh .github/workflows/installer/install.sh + cd .github/workflows/installer + vc deploy --prod -t "$VERCEL_TOKEN" diff --git a/.github/workflows/installer/.gitignore b/.github/workflows/installer/.gitignore new file mode 100644 index 000000000..f66fce310 --- /dev/null +++ b/.github/workflows/installer/.gitignore @@ -0,0 +1 @@ +install.sh diff --git a/.github/workflows/installer/.vercelignore b/.github/workflows/installer/.vercelignore new file mode 100644 index 000000000..41b233364 --- /dev/null +++ b/.github/workflows/installer/.vercelignore @@ -0,0 +1,2 @@ +/* +!/install.sh diff --git a/.github/workflows/installer/vercel.json b/.github/workflows/installer/vercel.json new file mode 100644 index 000000000..524dc3c0f --- /dev/null +++ b/.github/workflows/installer/vercel.json @@ -0,0 +1,23 @@ +{ + "headers": [ + { + "source": "/((?!favicon.ico).*)", + "headers": [ + { + "key": "Content-Type", + "value": "text/plain" + }, + { + "key": "Content-Disposition", + "value": "inline; filename=\"install.sh\"" + } + ] + } + ], + "rewrites": [ + { + "source": "/((?!favicon.ico|install.sh).*)", + "destination": "/install.sh" + } + ] +} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 50e00f9c9..de7d98262 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,29 +7,26 @@ on: branches: - master push: - branches: + branches: - master concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read # to fetch code (actions/checkout) + jobs: tests: name: Run tests - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest if: github.repository == 'ohmyzsh/ohmyzsh' - strategy: - matrix: - os: [ubuntu-latest, macos-latest] steps: - name: Set up git repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install zsh - if: runner.os == 'Linux' run: sudo apt-get update; sudo apt-get install zsh - - name: Test installer - run: sh ./tools/install.sh - name: Check syntax run: | for file in ./oh-my-zsh.sh \ diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml index b2219893d..2c2a1cdaa 100644 --- a/.github/workflows/project.yml +++ b/.github/workflows/project.yml @@ -9,14 +9,21 @@ concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: {} jobs: add-to-project: name: Add to project runs-on: ubuntu-latest if: github.repository == 'ohmyzsh/ohmyzsh' - env: - GITHUB_TOKEN: ${{ secrets.PROJECT_TOKEN }} steps: + - name: Authenticate as @ohmyzsh + id: generate_token + uses: ohmyzsh/github-app-token@v2 + with: + app_id: ${{ secrets.OHMYZSH_APP_ID }} + private_key: ${{ secrets.OHMYZSH_APP_PRIVATE_KEY }} + - name: Store app token + run: echo "GH_TOKEN=${{ steps.generate_token.outputs.token }}" >> "$GITHUB_ENV" - name: Read project data env: ORGANIZATION: ohmyzsh @@ -26,24 +33,25 @@ jobs: gh api graphql -f query=' query($org: String!, $number: Int!) { organization(login: $org){ - projectNext(number: $number) { + projectV2(number: $number) { id fields(first:20) { nodes { - id - name + ... on ProjectV2Field { + id + name + } } } } } - } - ' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json + }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json # Parse project data cat >> $GITHUB_ENV <> $GITHUB_ENV @@ -107,23 +115,27 @@ jobs: $theme_field: ID! $theme_value: String! ) { - set_plugin: updateProjectNextItemField(input: { + set_plugin: updateProjectV2ItemFieldValue(input: { projectId: $project itemId: $item fieldId: $plugin_field - value: $plugin_value + value: { + text: $plugin_value + } }) { - projectNextItem { + projectV2Item { id } } - set_theme: updateProjectNextItemField(input: { + set_theme: updateProjectV2ItemFieldValue(input: { projectId: $project itemId: $item fieldId: $theme_field - value: $theme_value + value: { + text: $theme_value + } }) { - projectNextItem { + projectV2Item { id } } @@ -132,4 +144,3 @@ jobs: -f plugin_field=$PLUGIN_FIELD_ID -f plugin_value=$PLUGIN \ -f theme_field=$THEME_FIELD_ID -f theme_value=$THEME \ --silent - diff --git a/.gitignore b/.gitignore index ec24a19bb..10bd4bebc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ cache/ log/ *.swp .DS_Store + +# editor configs +.vscode +.idea diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..a8f5a14b0 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "printWidth": 110, + "proseWrap": "always" +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 59cf96012..6c8b8446e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,13 +35,13 @@ you would make is not already covered. Please be so kind as to [search](#use-the-search-luke) for any open issue already covering your problem. -If you find one, comment on it so we can know there are more people experiencing it. +If you find one, comment on it, so we know more people are experiencing it. If not, look at the [Troubleshooting](https://github.com/ohmyzsh/ohmyzsh/wiki/Troubleshooting) page for instructions on how to gather data to better debug your problem. Then, you can go ahead and create an issue with as much detail as you can provide. -It should include the data gathered as indicated above, along with: +It should include the data gathered as indicated above, along with the following: 1. How to reproduce the problem 2. What the correct behavior should be @@ -57,7 +57,7 @@ We will do our very best to help you. Please be so kind as to [search](#use-the-search-luke) for any open issue already covering your suggestion. -If you find one, comment on it so we can know there are more people supporting it. +If you find one, comment on it, so we know more people are supporting it. If not, you can go ahead and create an issue. Please copy to anyone relevant (e.g. plugin maintainers) by mentioning their GitHub handle (starting with `@`) in your message. @@ -84,7 +84,7 @@ your [problem](#you-have-a-problem), and any pending/merged/rejected PR covering If the solution is already reported, try it out and +1 the pull request if the solution works ok. On the other hand, if you think your solution is better, post -it with a reference to the other one so we can have both solutions to compare. +it with reference to the other one so we can have both solutions to compare. If not, then go ahead and submit a PR. Please copy to anyone relevant (e.g. plugin maintainers) by mentioning their GitHub handle (starting with `@`) in your message. @@ -113,14 +113,14 @@ This has become an issue for two opposing reasons: - Some users want to have their personal aliases in Oh My Zsh. - Some users don't want any aliases at all and feel that there are too many. -Because of this, from now on we're requiring that new aliases follow these conditions: +Because of this, from now on, we require that new aliases follow these conditions: 1. They will be used by many people, not just a few. 2. The aliases will be used many times and for common tasks. 3. Prefer one generic alias over many specific ones. 4. When justifying the need for an alias, talk about workflows where you'll use it, preferably in combination with other aliases. -5. If there exists a command with the same name, look for a different alias name. +5. If a command with the same name exists, look for a different alias name. This list is not exhaustive! Please remember that your alias will be in the machines of many people, so it should be justified why they should have it. @@ -214,7 +214,7 @@ type(scope)!: subject ``` - `subject`: a brief description of the changes. This will be displayed in the changelog. If you need - to specify other details you can use the commit body but it won't be visible. + to specify other details, you can use the commit body, but it won't be visible. Formatting tricks: the commit subject may contain: @@ -231,9 +231,9 @@ type(scope)!: subject ### Style -Try to keep the first commit line short. This is harder to do using this commit style but try to be -concise and if you need more space, you can use the commit body. Try to make sure that the commit -subject is clear and precise enough that users will know what change by just looking at the changelog. +Try to keep the first commit line short. It's harder to do using this commit style but try to be +concise, and if you need more space, you can use the commit body. Try to make sure that the commit +subject is clear and precise enough that users will know what changed by just looking at the changelog. ---- diff --git a/README.md b/README.md index 1e4b7ff70..98743432d 100644 --- a/README.md +++ b/README.md @@ -13,38 +13,42 @@ Finally, you'll begin to get the sort of attention that you have always felt you To learn more, visit [ohmyz.sh](https://ohmyz.sh), follow [@ohmyzsh](https://twitter.com/ohmyzsh) on Twitter, and join us on [Discord](https://discord.gg/ohmyzsh). [![CI](https://github.com/ohmyzsh/ohmyzsh/workflows/CI/badge.svg)](https://github.com/ohmyzsh/ohmyzsh/actions?query=workflow%3ACI) -[![Follow @ohmyzsh](https://img.shields.io/twitter/follow/ohmyzsh?label=Follow+@ohmyzsh&style=flat)](https://twitter.com/intent/follow?screen_name=ohmyzsh) +[![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/ohmyzsh?label=%40ohmyzsh&logo=x&style=flat)](https://twitter.com/intent/follow?screen_name=ohmyzsh) +[![Mastodon Follow](https://img.shields.io/mastodon/follow/111169632522566717?label=%40ohmyzsh&domain=https%3A%2F%2Fmstdn.social&logo=mastodon&style=flat)](https://mstdn.social/@ohmyzsh) [![Discord server](https://img.shields.io/discord/642496866407284746)](https://discord.gg/ohmyzsh) [![Gitpod ready](https://img.shields.io/badge/Gitpod-ready-blue?logo=gitpod)](https://gitpod.io/#https://github.com/ohmyzsh/ohmyzsh) -[![huntr.dev](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev/bounties/disclose/?utm_campaign=ohmyzsh%2Fohmyzsh&utm_medium=social&utm_source=github&target=https%3A%2F%2Fgithub.com%2Fohmyzsh%2Fohmyzsh)
Table of Contents - [Getting Started](#getting-started) + - [Operating System Compatibility](#operating-system-compatibility) - [Prerequisites](#prerequisites) - [Basic Installation](#basic-installation) - - [Manual inspection](#manual-inspection) + - [Manual Inspection](#manual-inspection) - [Using Oh My Zsh](#using-oh-my-zsh) - [Plugins](#plugins) - [Enabling Plugins](#enabling-plugins) - [Using Plugins](#using-plugins) - [Themes](#themes) - - [Selecting a Theme](#selecting-a-theme) + - [Selecting A Theme](#selecting-a-theme) - [FAQ](#faq) - [Advanced Topics](#advanced-topics) - [Advanced Installation](#advanced-installation) - [Custom Directory](#custom-directory) - - [Unattended install](#unattended-install) - - [Installing from a forked repository](#installing-from-a-forked-repository) + - [Unattended Install](#unattended-install) + - [Installing From A Forked Repository](#installing-from-a-forked-repository) - [Manual Installation](#manual-installation) - [Installation Problems](#installation-problems) - - [Custom Plugins and Themes](#custom-plugins-and-themes) + - [Custom Plugins And Themes](#custom-plugins-and-themes) + - [Enable GNU ls In macOS And freeBSD Systems](#enable-gnu-ls-in-macos-and-freebsd-systems) + - [Skip Aliases](#skip-aliases) - [Getting Updates](#getting-updates) + - [Updates Verbosity](#updates-verbosity) - [Manual Updates](#manual-updates) - [Uninstalling Oh My Zsh](#uninstalling-oh-my-zsh) -- [How do I contribute to Oh My Zsh?](#how-do-i-contribute-to-oh-my-zsh) - - [Do NOT send us themes](#do-not-send-us-themes) +- [How Do I Contribute To Oh My Zsh?](#how-do-i-contribute-to-oh-my-zsh) + - [Do Not Send Us Themes](#do-not-send-us-themes) - [Contributors](#contributors) - [Follow Us](#follow-us) - [Merchandise](#merchandise) @@ -55,9 +59,21 @@ To learn more, visit [ohmyz.sh](https://ohmyz.sh), follow [@ohmyzsh](https://twi ## Getting Started +### Operating System Compatibility + +| O/S | Status | +| :------------- | :-----: | +| Android | ✅ | +| freeBSD | ✅ | +| LCARS | 🛸 | +| Linux | ✅ | +| macOS | ✅ | +| OS/2 Warp | ❌ | +| Windows (WSL2) | ✅ | + + ### Prerequisites -- A Unix-like operating system: macOS, Linux, BSD. On Windows: WSL2 is preferred, but cygwin or msys also mostly work. - [Zsh](https://www.zsh.org) should be installed (v4.3.9 or more recent is fine but we prefer 5.0.8 and newer). If not pre-installed (run `zsh --version` to confirm), check the following wiki instructions here: [Installing ZSH](https://github.com/ohmyzsh/ohmyzsh/wiki/Installing-ZSH) - `curl` or `wget` should be installed - `git` should be installed (recommended v2.4.11 or higher) @@ -72,9 +88,17 @@ Oh My Zsh is installed by running one of the following commands in your terminal | **wget** | `sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"` | | **fetch** | `sh -c "$(fetch -o - https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"` | +Alternatively, the installer is also mirrored outside GitHub. Using this URL instead may be required if you're in a country like India or China, that blocks `raw.githubusercontent.com`: + +| Method | Command | +| :-------- | :------------------------------------------------------------------------------------------------ | +| **curl** | `sh -c "$(curl -fsSL https://install.ohmyz.sh/)"` | +| **wget** | `sh -c "$(wget -O- https://install.ohmyz.sh/)"` | +| **fetch** | `sh -c "$(fetch -o - https://install.ohmyz.sh/)"` | + _Note that any previous `.zshrc` will be renamed to `.zshrc.pre-oh-my-zsh`. After installation, you can move the configuration you want to preserve into the new `.zshrc`._ -#### Manual inspection +#### Manual Inspection It's a good idea to inspect the install script from projects you don't yet know. You can do that by downloading the install script first, looking through it so everything looks normal, @@ -85,6 +109,8 @@ wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh sh install.sh ``` +If the above URL times out or otherwise fails, you may have to substitute the URL for `https://install.ohmyz.sh` to be able to get the script. + ## Using Oh My Zsh ### Plugins @@ -123,7 +149,7 @@ Each built-in plugin includes a **README**, documenting it. This README should s We'll admit it. Early in the Oh My Zsh world, we may have gotten a bit too theme happy. We have over one hundred and fifty themes now bundled. Most of them have [screenshots](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes) on the wiki (We are working on updating this!). Check them out! -#### Selecting a Theme +#### Selecting A Theme _Robby's theme is the default one. It's not the fanciest one. It's not the simplest one. It's just the right one (for him)._ @@ -194,7 +220,7 @@ like this: ZSH="$HOME/.dotfiles/oh-my-zsh" sh install.sh ``` -#### Unattended install +#### Unattended Install If you're running the Oh My Zsh install script as part of an automated install, you can pass the `--unattended` flag to the `install.sh` script. This will have the effect of not trying to change @@ -204,7 +230,9 @@ the default shell, and it also won't run `zsh` when the installation has finishe sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended ``` -#### Installing from a forked repository +If you're in China, India, or another country that blocks `raw.githubusercontent.com`, you may have to substitute the URL for `https://install.ohmyz.sh` for it to install. + +#### Installing From A Forked Repository The install script also accepts these variables to allow installation of a different repository: @@ -229,19 +257,19 @@ REPO=apjanke/oh-my-zsh BRANCH=edge sh install.sh #### Manual Installation -##### 1. Clone the repository +##### 1. Clone The Repository ```sh git clone https://github.com/ohmyzsh/ohmyzsh.git ~/.oh-my-zsh ``` -##### 2. _Optionally_, backup your existing `~/.zshrc` file +##### 2. _Optionally_, Backup Your Existing `~/.zshrc` File ```sh cp ~/.zshrc ~/.zshrc.orig ``` -##### 3. Create a new zsh configuration file +##### 3. Create A New Zsh Configuration File You can create a new zsh config file by copying the template that we have included for you. @@ -249,7 +277,7 @@ You can create a new zsh config file by copying the template that we have includ cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc ``` -##### 4. Change your default shell +##### 4. Change Your Default Shell ```sh chsh -s $(which zsh) @@ -257,7 +285,7 @@ chsh -s $(which zsh) You must log out from your user session and log back in to see this change. -##### 5. Initialize your new zsh configuration +##### 5. Initialize Your New Zsh Configuration Once you open up a new terminal window, it should load zsh with Oh My Zsh's configuration. @@ -268,7 +296,7 @@ If you have any hiccups installing, here are a few common fixes. - You _might_ need to modify your `PATH` in `~/.zshrc` if you're not able to find some commands after switching to `oh-my-zsh`. - If you installed manually or changed the install location, check the `ZSH` environment variable in `~/.zshrc`. -### Custom Plugins and Themes +### Custom Plugins And Themes If you want to override any of the default behaviors, just add a new file (ending in `.zsh`) in the `custom/` directory. @@ -276,6 +304,72 @@ If you have many functions that go well together, you can put them as a `XYZ.plu If you would like to override the functionality of a plugin distributed with Oh My Zsh, create a plugin of the same name in the `custom/plugins/` directory and it will be loaded instead of the one in `plugins/`. +### Enable GNU ls In macOS And freeBSD Systems + + + +The default behaviour in Oh My Zsh is to use BSD `ls` in macOS and freeBSD systems. If GNU `ls` is installed +(as `gls` command), you can choose to use it instead. To do it, you can use zstyle-based config before +sourcing `oh-my-zsh.sh`: + +```zsh +zstyle ':omz:lib:theme-and-appearance' gnu-ls yes +``` + +_Note: this is not compatible with `DISABLE_LS_COLORS=true`_ + +### Skip Aliases + + + +If you want to skip default Oh My Zsh aliases (those defined in `lib/*` files) or plugin aliases, +you can use the settings below in your `~/.zshrc` file, **before Oh My Zsh is loaded**. Note that +there are many different ways to skip aliases, depending on your needs. + +```sh +# Skip all aliases, in lib files and enabled plugins +zstyle ':omz:*' aliases no + +# Skip all aliases in lib files +zstyle ':omz:lib:*' aliases no +# Skip only aliases defined in the directories.zsh lib file +zstyle ':omz:lib:directories' aliases no + +# Skip all plugin aliases +zstyle ':omz:plugins:*' aliases no +# Skip only the aliases from the git plugin +zstyle ':omz:plugins:git' aliases no +``` + +You can combine these in other ways taking into account that more specific scopes takes precedence: + +```sh +# Skip all plugin aliases, except for the git plugin +zstyle ':omz:plugins:*' aliases no +zstyle ':omz:plugins:git' aliases yes +``` + +A previous version of this feature was using the setting below, which has been removed: + +```sh +zstyle ':omz:directories' aliases no +``` + +Instead, you can now use the following: + +```sh +zstyle ':omz:lib:directories' aliases no +``` + +#### Notice + +> This feature is currently in a testing phase and it may be subject to change in the future. +> It is also not currently compatible with plugin managers such as zpm or zinit, which don't +> source the init script (`oh-my-zsh.sh`) where this feature is implemented in. + +> It is also not currently aware of "aliases" that are defined as functions. Example of such +> are `gccd`, `ggf`, or `ggl` functions from the git plugin. + ## Getting Updates By default, you will be prompted to check for updates every 2 weeks. You can choose other update modes by adding a line to your `~/.zshrc` file, **before Oh My Zsh is loaded**: @@ -307,6 +401,18 @@ zstyle ':omz:update' frequency 7 zstyle ':omz:update' frequency 0 ``` +### Updates Verbosity + +You can also limit the update verbosity with the following settings: + +```sh +zstyle ':omz:update' verbose default # default update prompt + +zstyle ':omz:update' verbose minimal # only few lines + +zstyle ':omz:update' verbose silent # only errors +``` + ### Manual Updates If you'd like to update at any point in time (maybe someone just released a new plugin and you don't want to wait a week?) you just need to run: @@ -323,7 +429,7 @@ Oh My Zsh isn't for everyone. We'll miss you, but we want to make this an easy b If you want to uninstall `oh-my-zsh`, just run `uninstall_oh_my_zsh` from the command-line. It will remove itself and revert your previous `bash` or `zsh` configuration. -## How do I contribute to Oh My Zsh? +## How Do I Contribute To Oh My Zsh? Before you participate in our delightful community, please read the [code of conduct](CODE_OF_CONDUCT.md). @@ -333,7 +439,7 @@ We also need people to test out pull requests. So take a look through [the open See [Contributing](CONTRIBUTING.md) for more details. -### Do NOT send us themes +### Do Not Send Us Themes We have (more than) enough themes for the time being. Please add your theme to the [external themes](https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes) wiki page. @@ -364,4 +470,4 @@ Oh My Zsh is released under the [MIT license](LICENSE.txt). ![Planet Argon](https://pa-github-assets.s3.amazonaws.com/PARGON_logo_digital_COL-small.jpg) -Oh My Zsh was started by the team at [Planet Argon](https://www.planetargon.com/?utm_source=github), a [Ruby on Rails development agency](https://www.planetargon.com/skills/ruby-on-rails-development?utm_source=github). Check out our [other open source projects](https://www.planetargon.com/open-source?utm_source=github). +Oh My Zsh was started by the team at [Planet Argon](https://www.planetargon.com/?utm_source=github), a [Ruby on Rails development agency](http://www.planetargon.com/services/ruby-on-rails-development?utm_source=github). Check out our [other open source projects](https://www.planetargon.com/open-source?utm_source=github). diff --git a/SECURITY.md b/SECURITY.md index 7e5c8eed0..ae7458ee2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -17,8 +17,7 @@ In the near future we will introduce versioning, so expect this section to chang **Do not submit an issue or pull request**: this might reveal the vulnerability. -Instead, you should email the maintainers directly at: [**security@ohmyz.sh**](mailto:security@ohmyz.sh). +Instead, you should email the maintainers directly at: [**security@ohmyz.sh**](mailto:security@ohmyz.sh), +or using the link to [privately report a vulnerability with GitHub](https://github.com/ohmyzsh/ohmyzsh/security/advisories/new). We will deal with the vulnerability privately and submit a patch as soon as possible. - -You can also submit your vulnerability report to [huntr.dev](https://huntr.dev/bounties/disclose/?utm_campaign=ohmyzsh%2Fohmyzsh&utm_medium=social&utm_source=github&target=https%3A%2F%2Fgithub.com%2Fohmyzsh%2Fohmyzsh) and see if you can get a bounty reward. diff --git a/custom/example.zsh b/custom/example.zsh index c505a9673..21a8d8be7 100644 --- a/custom/example.zsh +++ b/custom/example.zsh @@ -1,10 +1,12 @@ -# You can put files here to add functionality separated per file, which -# will be ignored by git. -# Files on the custom/ directory will be automatically loaded by the init -# script, in alphabetical order. - -# For example: add yourself some shortcuts to projects you often work on. -# +# Put files in this folder to add your own custom functionality. +# See: https://github.com/ohmyzsh/ohmyzsh/wiki/Customization +# +# Files in the custom/ directory will be: +# - loaded automatically by the init script, in alphabetical order +# - loaded last, after all built-ins in the lib/ directory, to override them +# - ignored by git by default +# +# Example: add custom/shortcuts.zsh for shortcuts to your local projects +# # brainstormr=~/Projects/development/planetargon/brainstormr # cd $brainstormr -# diff --git a/custom/plugins/example/example.plugin.zsh b/custom/plugins/example/example.plugin.zsh index 406f27445..83611fe3f 100644 --- a/custom/plugins/example/example.plugin.zsh +++ b/custom/plugins/example/example.plugin.zsh @@ -1,2 +1,3 @@ # Add your own custom plugins in the custom/plugins directory. Plugins placed # here will override ones with the same name in the main plugins directory. +# See: https://github.com/ohmyzsh/ohmyzsh/wiki/Customization#overriding-and-adding-plugins diff --git a/custom/themes/example.zsh-theme b/custom/themes/example.zsh-theme index ef8f1c630..494d029e8 100644 --- a/custom/themes/example.zsh-theme +++ b/custom/themes/example.zsh-theme @@ -1,4 +1,6 @@ # Put your custom themes in this folder. +# See: https://github.com/ohmyzsh/ohmyzsh/wiki/Customization#overriding-and-adding-themes +# # Example: PROMPT="%{$fg[red]%}%n%{$reset_color%}@%{$fg[blue]%}%m %{$fg[yellow]%}%~ %{$reset_color%}%% " diff --git a/lib/cli.zsh b/lib/cli.zsh index db659c11f..561c1b98b 100644 --- a/lib/cli.zsh +++ b/lib/cli.zsh @@ -11,7 +11,7 @@ function omz { # Subcommand functions start with _ so that they don't # appear as completion entries when looking for `omz` - (( $+functions[_omz::$command] )) || { + (( ${+functions[_omz::$command]} )) || { _omz::help return 1 } @@ -241,21 +241,21 @@ function _omz::plugin::disable { # Remove plugins substitution awk script local awk_subst_plugins="\ - gsub(/\s+(${(j:|:)dis_plugins})/, \"\") # with spaces before - gsub(/(${(j:|:)dis_plugins})\s+/, \"\") # with spaces after + gsub(/[ \t]+(${(j:|:)dis_plugins})/, \"\") # with spaces before + gsub(/(${(j:|:)dis_plugins})[ \t]+/, \"\") # with spaces after gsub(/\((${(j:|:)dis_plugins})\)/, \"\") # without spaces (only plugin) " # Disable plugins awk script local awk_script=" # if plugins=() is in oneline form, substitute disabled plugins and go to next line -/^\s*plugins=\([^#]+\).*\$/ { +/^[ \t]*plugins=\([^#]+\).*\$/ { $awk_subst_plugins print \$0 next } # if plugins=() is in multiline form, enable multi flag and disable plugins if they're there -/^\s*plugins=\(/ { +/^[ \t]*plugins=\(/ { multi=1 $awk_subst_plugins print \$0 @@ -330,14 +330,14 @@ function _omz::plugin::enable { # Enable plugins awk script local awk_script=" # if plugins=() is in oneline form, substitute ) with new plugins and go to the next line -/^\s*plugins=\([^#]+\).*\$/ { +/^[ \t]*plugins=\([^#]+\).*\$/ { sub(/\)/, \" $add_plugins&\") print \$0 next } # if plugins=() is in multiline form, enable multi flag -/^\s*plugins=\(/ { +/^[ \t]*plugins=\(/ { multi=1 } @@ -416,14 +416,14 @@ function _omz::plugin::list { if (( ${#custom_plugins} )); then print -P "%U%BCustom plugins%b%u:" - print -l ${(q-)custom_plugins} | column -x + print -lac ${(q-)custom_plugins} fi if (( ${#builtin_plugins} )); then (( ${#custom_plugins} )) && echo # add a line of separation print -P "%U%BBuilt-in plugins%b%u:" - print -l ${(q-)builtin_plugins} | column -x + print -lac ${(q-)builtin_plugins} fi } @@ -674,13 +674,13 @@ function _omz::theme::list { # Print custom themes if there are any if (( ${#custom_themes} )); then print -P "%U%BCustom themes%b%u:" - print -l ${(q-)custom_themes} | column -x + print -lac ${(q-)custom_themes} echo fi # Print built-in themes print -P "%U%BBuilt-in themes%b%u:" - print -l ${(q-)builtin_themes} | column -x + print -lac ${(q-)builtin_themes} } function _omz::theme::set { @@ -699,9 +699,9 @@ function _omz::theme::set { # Enable theme in .zshrc local awk_script=' -!set && /^\s*ZSH_THEME=[^#]+.*$/ { +!set && /^[ \t]*ZSH_THEME=[^#]+.*$/ { set=1 - sub(/^\s*ZSH_THEME=[^#]+.*$/, "ZSH_THEME=\"'$1'\" # set by `omz`") + sub(/^[ \t]*ZSH_THEME=[^#]+.*$/, "ZSH_THEME=\"'$1'\" # set by `omz`") print $0 next } @@ -776,10 +776,11 @@ function _omz::update { local last_commit=$(builtin cd -q "$ZSH"; git rev-parse HEAD) # Run update script + zstyle -s ':omz:update' verbose verbose_mode || verbose_mode=default if [[ "$1" != --unattended ]]; then - ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" --interactive || return $? + ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" -i -v $verbose_mode || return $? else - ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" || return $? + ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" -v $verbose_mode || return $? fi # Update last updated file diff --git a/lib/clipboard.zsh b/lib/clipboard.zsh index ad83fc4b2..5d149f056 100644 --- a/lib/clipboard.zsh +++ b/lib/clipboard.zsh @@ -57,9 +57,12 @@ function detect-clipboard() { elif [[ "${OSTYPE}" == (cygwin|msys)* ]]; then function clipcopy() { cat "${1:-/dev/stdin}" > /dev/clipboard; } function clippaste() { cat /dev/clipboard; } + elif (( $+commands[clip.exe] )) && (( $+commands[powershell.exe] )); then + function clipcopy() { cat "${1:-/dev/stdin}" | clip.exe; } + function clippaste() { powershell.exe -noprofile -command Get-Clipboard; } elif [ -n "${WAYLAND_DISPLAY:-}" ] && (( ${+commands[wl-copy]} )) && (( ${+commands[wl-paste]} )); then function clipcopy() { cat "${1:-/dev/stdin}" | wl-copy &>/dev/null &|; } - function clippaste() { wl-paste; } + function clippaste() { wl-paste --no-newline; } elif [ -n "${DISPLAY:-}" ] && (( ${+commands[xsel]} )); then function clipcopy() { cat "${1:-/dev/stdin}" | xsel --clipboard --input; } function clippaste() { xsel --clipboard --output; } @@ -81,9 +84,6 @@ function detect-clipboard() { elif [ -n "${TMUX:-}" ] && (( ${+commands[tmux]} )); then function clipcopy() { tmux load-buffer "${1:--}"; } function clippaste() { tmux save-buffer -; } - elif [[ $(uname -r) = *icrosoft* ]]; then - function clipcopy() { cat "${1:-/dev/stdin}" | clip.exe; } - function clippaste() { powershell.exe -noprofile -command Get-Clipboard; } else function _retry_clipboard_detection_or_fail() { local clipcmd="${1}"; shift @@ -100,8 +100,8 @@ function detect-clipboard() { fi } -# Detect at startup. A non-zero exit here indicates that the dummy clipboards were set, -# which is not really an error. If the user calls them, they will attempt to redetect -# (for example, perhaps the user has now installed xclip) and then either print an error -# or proceed successfully. -detect-clipboard || true +function clipcopy clippaste { + unfunction clipcopy clippaste + detect-clipboard || true # let one retry + "$0" "$@" +} diff --git a/lib/completion.zsh b/lib/completion.zsh index 2c5695487..63379b53f 100644 --- a/lib/completion.zsh +++ b/lib/completion.zsh @@ -18,9 +18,9 @@ if [[ "$CASE_SENSITIVE" = true ]]; then zstyle ':completion:*' matcher-list 'r:|=*' 'l:|=* r:|=*' else if [[ "$HYPHEN_INSENSITIVE" = true ]]; then - zstyle ':completion:*' matcher-list 'm:{a-zA-Z-_}={A-Za-z_-}' 'r:|=*' 'l:|=* r:|=*' + zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]-_}={[:upper:][:lower:]_-}' 'r:|=*' 'l:|=* r:|=*' else - zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|=*' 'l:|=* r:|=*' + zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' 'r:|=*' 'l:|=* r:|=*' fi fi unset CASE_SENSITIVE HYPHEN_INSENSITIVE diff --git a/lib/correction.zsh b/lib/correction.zsh index 4259d3418..ba9664fcb 100644 --- a/lib/correction.zsh +++ b/lib/correction.zsh @@ -1,13 +1,8 @@ if [[ "$ENABLE_CORRECTION" == "true" ]]; then alias cp='nocorrect cp' - alias ebuild='nocorrect ebuild' - alias gist='nocorrect gist' - alias heroku='nocorrect heroku' - alias hpodder='nocorrect hpodder' alias man='nocorrect man' alias mkdir='nocorrect mkdir' alias mv='nocorrect mv' - alias mysql='nocorrect mysql' alias sudo='nocorrect sudo' alias su='nocorrect su' diff --git a/lib/directories.zsh b/lib/directories.zsh index c62f56468..8927a56ad 100644 --- a/lib/directories.zsh +++ b/lib/directories.zsh @@ -1,8 +1,10 @@ # Changing/making/removing directory +setopt auto_cd setopt auto_pushd setopt pushd_ignore_dups setopt pushdminus + alias -g ...='../..' alias -g ....='../../..' alias -g .....='../../../..' diff --git a/lib/functions.zsh b/lib/functions.zsh index dfcc4d961..f5c671f9c 100644 --- a/lib/functions.zsh +++ b/lib/functions.zsh @@ -5,7 +5,7 @@ function zsh_stats() { } function uninstall_oh_my_zsh() { - env ZSH="$ZSH" sh "$ZSH/tools/uninstall.sh" + command env ZSH="$ZSH" sh "$ZSH/tools/uninstall.sh" } function upgrade_oh_my_zsh() { @@ -30,6 +30,13 @@ function open_command() { ;; esac + # If a URL is passed, $BROWSER might be set to a local browser within SSH. + # See https://github.com/ohmyzsh/ohmyzsh/issues/11098 + if [[ -n "$BROWSER" && "$1" = (http|https)://* ]]; then + "$BROWSER" "$@" + return + fi + ${=open_cmd} "$@" &>/dev/null } @@ -56,7 +63,7 @@ function takegit() { } function take() { - if [[ $1 =~ ^(https?|ftp).*\.tar\.(gz|bz2|xz)$ ]]; then + if [[ $1 =~ ^(https?|ftp).*\.(tar\.(gz|bz2|xz)|tgz)$ ]]; then takeurl "$1" elif [[ $1 =~ ^([A-Za-z0-9]\+@|https?|git|ssh|ftps?|rsync).*\.git/?$ ]]; then takegit "$1" @@ -175,6 +182,8 @@ function omz_urlencode() { fi # Use LC_CTYPE=C to process text byte-by-byte + # Note that this doesn't work in Termux, as it only has UTF-8 locale. + # Characters will be processed as UTF-8, which is fine for URLs. local i byte ord LC_ALL=C export LC_ALL local reserved=';/?:@&=+$,' @@ -199,6 +208,9 @@ function omz_urlencode() { else if [[ "$byte" == " " && -n $spaces_as_plus ]]; then url_str+="+" + elif [[ "$PREFIX" = *com.termux* ]]; then + # Termux does not have non-UTF8 locales, so just send the UTF-8 character directly + url_str+="$byte" else ord=$(( [##16] #byte )) url_str+="%$ord" diff --git a/lib/git.zsh b/lib/git.zsh index be9fa7e67..f049f73c2 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -19,6 +19,7 @@ function git_prompt_info() { local ref ref=$(__git_prompt_git symbolic-ref --short HEAD 2> /dev/null) \ + || ref=$(__git_prompt_git describe --tags --exact-match HEAD 2> /dev/null) \ || ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) \ || return 0 diff --git a/lib/grep.zsh b/lib/grep.zsh index a725e0f26..54e0f694e 100644 --- a/lib/grep.zsh +++ b/lib/grep.zsh @@ -24,8 +24,8 @@ else if [[ -n "$GREP_OPTIONS" ]]; then # export grep, egrep and fgrep settings alias grep="grep $GREP_OPTIONS" - alias egrep="egrep $GREP_OPTIONS" - alias fgrep="fgrep $GREP_OPTIONS" + alias egrep="grep -E $GREP_OPTIONS" + alias fgrep="grep -F $GREP_OPTIONS" # write to cache file if cache directory is writable if [[ -w "$ZSH_CACHE_DIR" ]]; then diff --git a/lib/misc.zsh b/lib/misc.zsh index 1f637083a..ff2017713 100644 --- a/lib/misc.zsh +++ b/lib/misc.zsh @@ -15,11 +15,17 @@ if [[ $DISABLE_MAGIC_FUNCTIONS != true ]]; then done fi -## jobs -setopt long_list_jobs +setopt multios # enable redirect to multiple streams: echo >file1 >file2 +setopt long_list_jobs # show long list format job notifications +setopt interactivecomments # recognize comments -env_default 'PAGER' 'less' -env_default 'LESS' '-R' +# define pager dependant on what is available (less or more) +if (( ${+commands[less]} )); then + env_default 'PAGER' 'less' + env_default 'LESS' '-R' +elif (( ${+commands[more]} )); then + env_default 'PAGER' 'more' +fi ## super user alias alias _='sudo ' @@ -30,6 +36,3 @@ if (( $+commands[ack-grep] )); then elif (( $+commands[ack] )); then alias afind='ack -il' fi - -# recognize comments -setopt interactivecomments diff --git a/lib/prompt_info_functions.zsh b/lib/prompt_info_functions.zsh index e5535848b..3dc9b6d10 100644 --- a/lib/prompt_info_functions.zsh +++ b/lib/prompt_info_functions.zsh @@ -18,6 +18,7 @@ function chruby_prompt_info \ vi_mode_prompt_info \ virtualenv_prompt_info \ jenv_prompt_info \ + azure_prompt_info \ tf_prompt_info \ { return 1 diff --git a/lib/termsupport.zsh b/lib/termsupport.zsh index 80ca7ef78..d170ffcbf 100644 --- a/lib/termsupport.zsh +++ b/lib/termsupport.zsh @@ -17,7 +17,7 @@ function title { : ${2=$1} case "$TERM" in - cygwin|xterm*|putty*|rxvt*|konsole*|ansi|mlterm*|alacritty|st*|foot) + cygwin|xterm*|putty*|rxvt*|konsole*|ansi|mlterm*|alacritty|st*|foot*|contour*) print -Pn "\e]2;${2:q}\a" # set window name print -Pn "\e]1;${1:q}\a" # set tab name ;; @@ -109,28 +109,55 @@ if [[ -z "$INSIDE_EMACS" || "$INSIDE_EMACS" = vterm ]]; then add-zsh-hook preexec omz_termsupport_preexec fi -# Keep Apple Terminal.app's current working directory updated -# Based on this answer: https://superuser.com/a/315029 -# With extra fixes to handle multibyte chars and non-UTF-8 locales +# Keep terminal emulator's current working directory correct, +# even if the current working directory path contains symbolic links +# +# References: +# - Apple's Terminal.app: https://superuser.com/a/315029 +# - iTerm2: https://iterm2.com/documentation-escape-codes.html (iTerm2 Extension / CurrentDir+RemoteHost) +# - Konsole: https://bugs.kde.org/show_bug.cgi?id=327720#c1 +# - libvte (gnome-terminal, mate-terminal, …): https://bugzilla.gnome.org/show_bug.cgi?id=675987#c14 +# Apparently it had a bug before ~2012 were it would display the unknown OSC 7 code +# +# As of May 2021 mlterm, PuTTY, rxvt, screen, termux & xterm simply ignore the unknown OSC. -if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]]; then - # Emits the control sequence to notify Terminal.app of the cwd - # Identifies the directory using a file: URI scheme, including - # the host name to disambiguate local vs. remote paths. - function update_terminalapp_cwd() { - emulate -L zsh - - # Percent-encode the host and path names. - local URL_HOST URL_PATH - URL_HOST="$(omz_urlencode -P $HOST)" || return 1 - URL_PATH="$(omz_urlencode -P $PWD)" || return 1 - - # Undocumented Terminal.app-specific control sequence - printf '\e]7;%s\a' "file://$URL_HOST$URL_PATH" - } - - # Use a precmd hook instead of a chpwd hook to avoid contaminating output - add-zsh-hook precmd update_terminalapp_cwd - # Run once to get initial cwd set - update_terminalapp_cwd +# Don't define the function if we're inside Emacs or in an SSH session (#11696) +if [[ -n "$INSIDE_EMACS" || -n "$SSH_CLIENT" || -n "$SSH_TTY" ]]; then + return fi + +# Don't define the function if we're in an unsupported terminal +case "$TERM" in + # all of these either process OSC 7 correctly or ignore entirely + xterm*|putty*|rxvt*|konsole*|mlterm*|alacritty|screen*|tmux*) ;; + contour*|foot*) ;; + *) + # Terminal.app and iTerm2 process OSC 7 correctly + case "$TERM_PROGRAM" in + Apple_Terminal|iTerm.app) ;; + *) return ;; + esac ;; +esac + +# Emits the control sequence to notify many terminal emulators +# of the cwd +# +# Identifies the directory using a file: URI scheme, including +# the host name to disambiguate local vs. remote paths. +function omz_termsupport_cwd { + # Percent-encode the host and path names. + local URL_HOST URL_PATH + URL_HOST="$(omz_urlencode -P $HOST)" || return 1 + URL_PATH="$(omz_urlencode -P $PWD)" || return 1 + + # Konsole errors if the HOST is provided + [[ -z "$KONSOLE_PROFILE_NAME" && -z "$KONSOLE_DBUS_SESSION" ]] || URL_HOST="" + + # common control sequence (OSC 7) to set current host and path + printf "\e]7;file://%s%s\e\\" "${URL_HOST}" "${URL_PATH}" +} + +# Use a precmd hook instead of a chpwd hook to avoid contaminating output +# i.e. when a script or function changes directory without `cd -q`, chpwd +# will be called the output may be swallowed by the script or function. +add-zsh-hook precmd omz_termsupport_cwd diff --git a/lib/theme-and-appearance.zsh b/lib/theme-and-appearance.zsh index 00947f72d..585e969d8 100644 --- a/lib/theme-and-appearance.zsh +++ b/lib/theme-and-appearance.zsh @@ -1,59 +1,81 @@ -# ls colors +# Sets color variable such as $fg, $bg, $color and $reset_color autoload -U colors && colors -# Enable ls colors +# Expand variables and commands in PROMPT variables +setopt prompt_subst + +# Prompt function theming defaults +ZSH_THEME_GIT_PROMPT_PREFIX="git:(" # Beginning of the git prompt, before the branch name +ZSH_THEME_GIT_PROMPT_SUFFIX=")" # End of the git prompt +ZSH_THEME_GIT_PROMPT_DIRTY="*" # Text to display if the branch is dirty +ZSH_THEME_GIT_PROMPT_CLEAN="" # Text to display if the branch is clean +ZSH_THEME_RUBY_PROMPT_PREFIX="(" +ZSH_THEME_RUBY_PROMPT_SUFFIX=")" + + +# Use diff --color if available +if command diff --color /dev/null{,} &>/dev/null; then + function diff { + command diff --color "$@" + } +fi + +# Don't set ls coloring if disabled +[[ "$DISABLE_LS_COLORS" != true ]] || return 0 + +# Default coloring for BSD-based ls export LSCOLORS="Gxfxcxdxbxegedabagacad" -# TODO organise this chaotic logic - -if [[ "$DISABLE_LS_COLORS" != "true" ]]; then - # Find the option for using colors in ls, depending on the version - if [[ "$OSTYPE" == netbsd* ]]; then - # On NetBSD, test if "gls" (GNU ls) is installed (this one supports colors); - # otherwise, leave ls as is, because NetBSD's ls doesn't support -G - gls --color -d . &>/dev/null && alias ls='gls --color=tty' - elif [[ "$OSTYPE" == openbsd* ]]; then - # On OpenBSD, "gls" (ls from GNU coreutils) and "colorls" (ls from base, - # with color and multibyte support) are available from ports. "colorls" - # will be installed on purpose and can't be pulled in by installing - # coreutils, so prefer it to "gls". - gls --color -d . &>/dev/null && alias ls='gls --color=tty' - colorls -G -d . &>/dev/null && alias ls='colorls -G' - elif [[ "$OSTYPE" == (darwin|freebsd)* ]]; then - # this is a good alias, it works by default just using $LSCOLORS - ls -G . &>/dev/null && alias ls='ls -G' - - # only use coreutils ls if there is a dircolors customization present ($LS_COLORS or .dircolors file) - # otherwise, gls will use the default color scheme which is ugly af - [[ -n "$LS_COLORS" || -f "$HOME/.dircolors" ]] && gls --color -d . &>/dev/null && alias ls='gls --color=tty' +# Default coloring for GNU-based ls +if [[ -z "$LS_COLORS" ]]; then + # Define LS_COLORS via dircolors if available. Otherwise, set a default + # equivalent to LSCOLORS (generated via https://geoff.greer.fm/lscolors) + if (( $+commands[dircolors] )); then + [[ -f "$HOME/.dircolors" ]] \ + && source <(dircolors -b "$HOME/.dircolors") \ + || source <(dircolors -b) else - # For GNU ls, we use the default ls color theme. They can later be overwritten by themes. - if [[ -z "$LS_COLORS" ]]; then - (( $+commands[dircolors] )) && eval "$(dircolors -b)" - fi - - ls --color -d . &>/dev/null && alias ls='ls --color=tty' || { ls -G . &>/dev/null && alias ls='ls -G' } - - # Take advantage of $LS_COLORS for completion as well. - zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" + export LS_COLORS="di=1;36:ln=35:so=32:pi=33:ex=31:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43" fi fi -# enable diff color if possible. -if command diff --color /dev/null /dev/null &>/dev/null; then - alias diff='diff --color' -fi +function test-ls-args { + local cmd="$1" # ls, gls, colorls, ... + local args="${@[2,-1]}" # arguments except the first one + command "$cmd" "$args" /dev/null &>/dev/null +} -setopt auto_cd -setopt multios -setopt prompt_subst +# Find the option for using colors in ls, depending on the version +case "$OSTYPE" in + netbsd*) + # On NetBSD, test if `gls` (GNU ls) is installed (this one supports colors); + # otherwise, leave ls as is, because NetBSD's ls doesn't support -G + test-ls-args gls --color && alias ls='gls --color=tty' + ;; + openbsd*) + # On OpenBSD, `gls` (ls from GNU coreutils) and `colorls` (ls from base, + # with color and multibyte support) are available from ports. + # `colorls` will be installed on purpose and can't be pulled in by installing + # coreutils (which might be installed for ), so prefer it to `gls`. + test-ls-args gls --color && alias ls='gls --color=tty' + test-ls-args colorls -G && alias ls='colorls -G' + ;; + (darwin|freebsd)*) + # This alias works by default just using $LSCOLORS + test-ls-args ls -G && alias ls='ls -G' + # Only use GNU ls if installed and there are user defaults for $LS_COLORS, + # as the default coloring scheme is not very pretty + zstyle -t ':omz:lib:theme-and-appearance' gnu-ls \ + && test-ls-args gls --color \ + && alias ls='gls --color=tty' + ;; + *) + if test-ls-args ls --color; then + alias ls='ls --color=tty' + elif test-ls-args ls -G; then + alias ls='ls -G' + fi + ;; +esac -[[ -n "$WINDOW" ]] && SCREEN_NO="%B$WINDOW%b " || SCREEN_NO="" - -# git theming default: Variables for theming the git info prompt -ZSH_THEME_GIT_PROMPT_PREFIX="git:(" # Prefix at the very beginning of the prompt, before the branch name -ZSH_THEME_GIT_PROMPT_SUFFIX=")" # At the very end of the prompt -ZSH_THEME_GIT_PROMPT_DIRTY="*" # Text to display if the branch is dirty -ZSH_THEME_GIT_PROMPT_CLEAN="" # Text to display if the branch is clean -ZSH_THEME_RUBY_PROMPT_PREFIX="(" -ZSH_THEME_RUBY_PROMPT_SUFFIX=")" +unfunction test-ls-args diff --git a/lib/vcs_info.zsh b/lib/vcs_info.zsh index e60938c14..be6d32ee9 100644 --- a/lib/vcs_info.zsh +++ b/lib/vcs_info.zsh @@ -38,7 +38,7 @@ # due to malicious input as a consequence of CVE-2021-45444, which affects # zsh versions from 5.0.3 to 5.8. # -autoload -Uz +X regexp-replace VCS_INFO_formats 2>/dev/null || return +autoload -Uz +X regexp-replace VCS_INFO_formats 2>/dev/null || return 0 # We use $tmp here because it's already a local variable in VCS_INFO_formats typeset PATCH='for tmp (base base-name branch misc revision subdir) hook_com[$tmp]="${hook_com[$tmp]//\%/%%}"' diff --git a/oh-my-zsh.sh b/oh-my-zsh.sh index 925ee46aa..137ca3b6f 100644 --- a/oh-my-zsh.sh +++ b/oh-my-zsh.sh @@ -1,14 +1,14 @@ +# ANSI formatting function (\033[m) +# 0: reset, 1: bold, 4: underline, 22: no bold, 24: no underline, 31: red, 33: yellow +omz_f() { + [ $# -gt 0 ] || return + IFS=";" printf "\033[%sm" $* +} +# If stdout is not a terminal ignore all formatting +[ -t 1 ] || omz_f() { :; } + # Protect against non-zsh execution of Oh My Zsh (use POSIX syntax here) [ -n "$ZSH_VERSION" ] || { - # ANSI formatting function (\033[m) - # 0: reset, 1: bold, 4: underline, 22: no bold, 24: no underline, 31: red, 33: yellow - omz_f() { - [ $# -gt 0 ] || return - IFS=";" printf "\033[%sm" $* - } - # If stdout is not a terminal ignore all formatting - [ -t 1 ] || omz_f() { :; } - omz_ptree() { # Get process tree of the current process pid=$$; pids="$pid" @@ -38,6 +38,15 @@ return 1 } +# Check if in emulation mode, if so early return +# https://github.com/ohmyzsh/ohmyzsh/issues/11686 +[[ "$(emulate)" = zsh ]] || { + printf "$(omz_f 1 31)Error:$(omz_f 22) Oh My Zsh can't be loaded in \`$(emulate)\` emulation mode.$(omz_f 0)\n" >&2 + return 1 +} + +unset -f omz_f + # If ZSH is not defined, use the current script's directory. [[ -z "$ZSH" ]] && export ZSH="${${(%):-%x}:a:h}" @@ -57,9 +66,7 @@ mkdir -p "$ZSH_CACHE_DIR/completions" (( ${fpath[(Ie)"$ZSH_CACHE_DIR/completions"]} )) || fpath=("$ZSH_CACHE_DIR/completions" $fpath) # Check for updates on initial load... -if [[ "$DISABLE_AUTO_UPDATE" != true ]]; then - source "$ZSH/tools/check_for_upgrade.sh" -fi +source "$ZSH/tools/check_for_upgrade.sh" # Initializes Oh My Zsh @@ -67,7 +74,7 @@ fi fpath=("$ZSH/functions" "$ZSH/completions" $fpath) # Load all stock functions (from $fpath files) called below. -autoload -U compaudit compinit +autoload -U compaudit compinit zrecompile # Set ZSH_CUSTOM to the path where your custom config files # and plugins exists, or else we will use the default custom/ @@ -142,22 +149,63 @@ EOF fi unset zcompdump_revision zcompdump_fpath zcompdump_refresh -# Load all of the config files in ~/oh-my-zsh that end in .zsh +# zcompile the completion dump file if the .zwc is older or missing. +if command mkdir "${ZSH_COMPDUMP}.lock" 2>/dev/null; then + zrecompile -q -p "$ZSH_COMPDUMP" + command rm -rf "$ZSH_COMPDUMP.zwc.old" "${ZSH_COMPDUMP}.lock" +fi + +_omz_source() { + local context filepath="$1" + + # Construct zstyle context based on path + case "$filepath" in + lib/*) context="lib:${filepath:t:r}" ;; # :t = lib_name.zsh, :r = lib_name + plugins/*) context="plugins:${filepath:h:t}" ;; # :h = plugins/plugin_name, :t = plugin_name + esac + + local disable_aliases=0 + zstyle -T ":omz:${context}" aliases || disable_aliases=1 + + # Back up alias names prior to sourcing + local -A aliases_pre galiases_pre + if (( disable_aliases )); then + aliases_pre=("${(@kv)aliases}") + galiases_pre=("${(@kv)galiases}") + fi + + # Source file from $ZSH_CUSTOM if it exists, otherwise from $ZSH + if [[ -f "$ZSH_CUSTOM/$filepath" ]]; then + source "$ZSH_CUSTOM/$filepath" + elif [[ -f "$ZSH/$filepath" ]]; then + source "$ZSH/$filepath" + fi + + # Unset all aliases that don't appear in the backed up list of aliases + if (( disable_aliases )); then + if (( #aliases_pre )); then + aliases=("${(@kv)aliases_pre}") + else + (( #aliases )) && unalias "${(@k)aliases}" + fi + if (( #galiases_pre )); then + galiases=("${(@kv)galiases_pre}") + else + (( #galiases )) && unalias "${(@k)galiases}" + fi + fi +} + +# Load all of the lib files in ~/oh-my-zsh/lib that end in .zsh # TIP: Add files you don't want in git to .gitignore -for config_file ("$ZSH"/lib/*.zsh); do - custom_config_file="$ZSH_CUSTOM/lib/${config_file:t}" - [[ -f "$custom_config_file" ]] && config_file="$custom_config_file" - source "$config_file" +for lib_file ("$ZSH"/lib/*.zsh); do + _omz_source "lib/${lib_file:t}" done -unset custom_config_file +unset lib_file # Load all of the plugins that were defined in ~/.zshrc for plugin ($plugins); do - if [[ -f "$ZSH_CUSTOM/plugins/$plugin/$plugin.plugin.zsh" ]]; then - source "$ZSH_CUSTOM/plugins/$plugin/$plugin.plugin.zsh" - elif [[ -f "$ZSH/plugins/$plugin/$plugin.plugin.zsh" ]]; then - source "$ZSH/plugins/$plugin/$plugin.plugin.zsh" - fi + _omz_source "plugins/$plugin/$plugin.plugin.zsh" done unset plugin @@ -185,3 +233,6 @@ if [[ -n "$ZSH_THEME" ]]; then echo "[oh-my-zsh] theme '$ZSH_THEME' not found" fi fi + +# set completion colors to be the same as `ls`, after theme has been loaded +[[ -z "$LS_COLORS" ]] || zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" diff --git a/plugins/1password/README.md b/plugins/1password/README.md index f6854da53..ace6da8e1 100644 --- a/plugins/1password/README.md +++ b/plugins/1password/README.md @@ -14,16 +14,18 @@ clipboard. ## `opswd` The `opswd` command is a wrapper around the `op` command. It takes a service -name as an argument and copies the password for that service to the clipboard. +name as an argument and copies the username, then the password for that service +to the clipboard, after confirmation on the user part. -If the service also contains a TOTP, it is copied to the clipboard after 10 seconds. -Finally, after 20 seconds, the clipboard is cleared. +If the service also contains a TOTP, it is copied to the clipboard after confirmation +on the user part. Finally, after 20 seconds, the clipboard is cleared. -The function has completion support, so you can use tab completion to select -which service you want to get. +For example, `opswd github.com` will put your GitHub username into your clipboard. Then, +it will ask for confirmation to continue, and copy the password to your clipboard. Finally, +if a TOTP is available, it will be copied to the clipboard after your confirmation. -For example, `opswd github.com` will put your GitHub password into your clipboard, and if -a TOTP is available, it will be copied to the clipboard after 10 seconds. +This function has completion support, so you can use tab completion to select which +service you want to get. > NOTE: you need to be signed in for `opswd` to work. If you are using biometric unlock, > 1Password CLI will automatically prompt you to sign in. See: diff --git a/plugins/1password/opswd b/plugins/1password/opswd index 57672807e..0f667d2ff 100644 --- a/plugins/1password/opswd +++ b/plugins/1password/opswd @@ -14,6 +14,17 @@ function opswd() { # If not logged in, print error and return op user list > /dev/null || return + local username + # Copy the username to the clipboard + if ! username=$(op item get "$service" --fields username 2>/dev/null); then + echo "error: could not obtain username for $service" + return 1 + fi + + echo -n "$username" | clipcopy + echo "✔ username for service $service copied to the clipboard. Press Enter to continue" + read + local password # Copy the password to the clipboard if ! password=$(op item get "$service" --fields password 2>/dev/null); then @@ -22,12 +33,13 @@ function opswd() { fi echo -n "$password" | clipcopy - echo "✔ password for $service copied to clipboard" + echo "✔ password for $service copied to clipboard. Press Enter to continue" + read - # If there's a one time password, copy it to the clipboard after 10 seconds + # If there's a one time password, copy it to the clipboard local totp if totp=$(op item get --otp "$service" 2>/dev/null) && [[ -n "$totp" ]]; then - sleep 10 && echo -n "$totp" | clipcopy + echo -n "$totp" | clipcopy echo "✔ TOTP for $service copied to clipboard" fi diff --git a/plugins/alias-finder/.zunit.yml b/plugins/alias-finder/.zunit.yml new file mode 100644 index 000000000..ae65f8ef2 --- /dev/null +++ b/plugins/alias-finder/.zunit.yml @@ -0,0 +1,9 @@ +tap: false +directories: + tests: tests + output: tests/_output + support: tests/_support +time_limit: 0 +fail_fast: false +allow_risky: false +verbose: true diff --git a/plugins/alias-finder/README.md b/plugins/alias-finder/README.md index 409f4b653..6c87c723a 100644 --- a/plugins/alias-finder/README.md +++ b/plugins/alias-finder/README.md @@ -2,45 +2,32 @@ This plugin searches the defined aliases and outputs any that match the command inputted. This makes learning new aliases easier. +## Usage + To use it, add `alias-finder` to the `plugins` array of your zshrc file: ``` plugins=(... alias-finder) ``` -## Usage -To see if there is an alias defined for the command, pass it as an argument to `alias-finder`. This can also run automatically before each command you input - add `ZSH_ALIAS_FINDER_AUTOMATIC=true` to your zshrc if you want this. +To enable it for every single command, set zstyle in your `~/.zshrc`. -## Options +```zsh +# ~/.zshrc + +zstyle ':omz:plugins:alias-finder' autoload yes # disabled by default +zstyle ':omz:plugins:alias-finder' longer yes # disabled by default +zstyle ':omz:plugins:alias-finder' exact yes # disabled by default +zstyle ':omz:plugins:alias-finder' cheaper yes # disabled by default +``` + +As you can see, options are also available with zstyle. + +### Options + +> In order to clarify, let's say `alias a=abc` has source 'abc' and destination 'a'. + +- Use `--longer` or `-l` to include aliases where the source is longer than the input (in other words, the source could contain the whole input). +- Use `--exact` or `-e` to avoid aliases where the source is shorter than the input (in other words, the source must be the same with the input). +- Use `--cheaper` or `-c` to avoid aliases where the destination is longer than the input (in other words, the destination must be the shorter than the input). -- Use `--longer` or `-l` to allow the aliases to be longer than the input (match aliases if they contain the input). -- Use `--exact` or `-e` to avoid matching aliases that are shorter than the input. -## Examples -``` -$ alias-finder "git pull" -gl='git pull' -g=git -``` -``` -$ alias-finder "web_search google oh my zsh" -google='web_search google' -``` -``` -$ alias-finder "git commit -v" -gc="git commit -v" -g=git -``` -``` -$ alias-finder -e "git commit -v" -gc='git commit -v' -``` -``` -$ alias-finder -l "git commit -v" -gc='git commit -v' -'gc!'='git commit -v --amend' -gca='git commit -v -a' -'gca!'='git commit -v -a --amend' -'gcan!'='git commit -v -a --no-edit --amend' -'gcans!'='git commit -v -a -s --no-edit --amend' -'gcn!'='git commit -v --no-edit --amend' -``` diff --git a/plugins/alias-finder/alias-finder.plugin.zsh b/plugins/alias-finder/alias-finder.plugin.zsh index caee9b5a3..5fdfbc835 100644 --- a/plugins/alias-finder/alias-finder.plugin.zsh +++ b/plugins/alias-finder/alias-finder.plugin.zsh @@ -1,44 +1,59 @@ alias-finder() { - local cmd="" exact="" longer="" wordStart="" wordEnd="" multiWordEnd="" - for i in $@; do - case $i in + local cmd=" " exact="" longer="" cheaper="" wordEnd="'{0,1}$" finder="" filter="" + + # build command and options + for c in "$@"; do + case $c in + # TODO: Remove backward compatibility (other than zstyle form) + # set options if exist -e|--exact) exact=true;; -l|--longer) longer=true;; - *) - if [[ -z $cmd ]]; then - cmd=$i - else - cmd="$cmd $i" - fi - ;; + -c|--cheaper) cheaper=true;; + # concatenate cmd + *) cmd="$cmd$c " ;; esac done - cmd=$(sed 's/[].\|$(){}?+*^[]/\\&/g' <<< $cmd) # adds escaping for grep - if (( $(wc -l <<< $cmd) == 1 )); then - while [[ $cmd != "" ]]; do - if [[ $longer = true ]]; then - wordStart="'{0,1}" - else - wordEnd="$" - multiWordEnd="'$" - fi - if [[ $cmd == *" "* ]]; then - local finder="'$cmd$multiWordEnd" - else - local finder=$wordStart$cmd$wordEnd - fi - alias | grep -E "=$finder" - if [[ $exact = true || $longer = true ]]; then - break - else - cmd=$(sed -E 's/ {0,1}[^ ]*$//' <<< $cmd) # removes last word - fi - done + + zstyle -t ':omz:plugins:alias-finder' longer && longer=true + zstyle -t ':omz:plugins:alias-finder' exact && exact=true + zstyle -t ':omz:plugins:alias-finder' cheaper && cheaper=true + + # format cmd for grep + ## - replace newlines with spaces + ## - trim both ends + ## - replace multiple spaces with one space + ## - add escaping character to special characters + cmd=$(echo -n "$cmd" | tr '\n' ' ' | xargs | tr -s '[:space:]' | sed 's/[].\|$(){}?+*^[]/\\&/g') + + if [[ $longer == true ]]; then + wordEnd="" # remove wordEnd to find longer aliases fi + + # find with alias and grep, removing last word each time until no more words + while [[ $cmd != "" ]]; do + finder="'{0,1}$cmd$wordEnd" + + # make filter to find only shorter results than current cmd + if [[ $cheaper == true ]]; then + cmdLen=$(echo -n "$cmd" | wc -c) + filter="^'{0,1}.{0,$((cmdLen - 1))}=" + fi + + alias | grep -E "$filter" | grep -E "=$finder" + + if [[ $exact == true ]]; then + break # because exact case is only one + elif [[ $longer = true ]]; then + break # because above grep command already found every longer aliases during first cycle + fi + + cmd=$(sed -E 's/ {0,}[^ ]*$//' <<< "$cmd") # remove last word + done } preexec_alias-finder() { - if [[ $ZSH_ALIAS_FINDER_AUTOMATIC = true ]]; then + # TODO: Remove backward compatibility (other than zstyle form) + zstyle -t ':omz:plugins:alias-finder' autoload && alias-finder $1 || if [[ $ZSH_ALIAS_FINDER_AUTOMATIC = true ]]; then alias-finder $1 fi } diff --git a/plugins/alias-finder/tests/_output/.gitkeep b/plugins/alias-finder/tests/_output/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/alias-finder/tests/_support/.gitkeep b/plugins/alias-finder/tests/_support/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/alias-finder/tests/_support/bootstrap b/plugins/alias-finder/tests/_support/bootstrap new file mode 100644 index 000000000..01076611e --- /dev/null +++ b/plugins/alias-finder/tests/_support/bootstrap @@ -0,0 +1,2 @@ +#!/usr/bin/env zsh +# Write your bootstrap code here diff --git a/plugins/alias-finder/tests/test_run.sh b/plugins/alias-finder/tests/test_run.sh new file mode 100644 index 000000000..6b7abebb6 --- /dev/null +++ b/plugins/alias-finder/tests/test_run.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env zunit + +@setup { + load ../alias-finder.plugin.zsh + + set_git_aliases() { + unalias -a # all + alias g="git" + alias gc="git commit" + alias gcv="git commit -v" + alias gcvs="git commit -v -S" + } +} + +@test 'find aliases that contain input' { + set_git_aliases + + run alias-finder "git" + + assert "${#lines[@]}" equals 1 + assert "${lines[1]}" same_as "g=git" +} + +@test 'find aliases that contain input with whitespaces at ends' { + set_git_aliases + + run alias-finder " git " + + assert "${#lines[@]}" equals 1 + assert "${lines[1]}" same_as "g=git" +} + +@test 'find aliases that contain multiple words' { + set_git_aliases + + run alias-finder "git commit -v" + + assert "${#lines[@]}" equals 3 + assert "${lines[1]}" same_as "gcv='git commit -v'" + assert "${lines[2]}" same_as "gc='git commit'" + assert "${lines[3]}" same_as "g=git" +} + +@test 'find alias that is the same with input when --exact option is set' { + set_git_aliases + + run alias-finder -e "git" + + assert "${#lines[@]}" equals 1 + assert "${lines[1]}" same_as "g=git" +} + +@test 'find alias that is the same with multiple words input when --exact option is set' { + set_git_aliases + + run alias-finder -e "git commit -v" + + assert "${#lines[@]}" equals 1 + assert "${lines[1]}" same_as "gcv='git commit -v'" +} + +@test 'find alias that is the same with or longer than input when --longer option is set' { + set_git_aliases + + run alias-finder -l "git" + + assert "${#lines[@]}" equals 4 + assert "${lines[1]}" same_as "g=git" + assert "${lines[2]}" same_as "gc='git commit'" + assert "${lines[3]}" same_as "gcv='git commit -v'" + assert "${lines[4]}" same_as "gcvs='git commit -v -S'" +} + +@test 'find alias that is the same with or longer than multiple words input when --longer option is set' { + set_git_aliases + + run alias-finder -l "git commit -v" + + assert "${#lines[@]}" equals 2 + assert "${lines[1]}" same_as "gcv='git commit -v'" + assert "${lines[2]}" same_as "gcvs='git commit -v -S'" +} + +@test 'find aliases including expensive (longer) than input' { + set_git_aliases + alias expensiveCommands="git commit" + + run alias-finder "git commit -v" + + assert "${#lines[@]}" equals 4 + assert "${lines[1]}" same_as "gcv='git commit -v'" + assert "${lines[2]}" same_as "expensiveCommands='git commit'" + assert "${lines[3]}" same_as "gc='git commit'" + assert "${lines[4]}" same_as "g=git" +} + +@test 'find aliases excluding expensive (longer) than input when --cheap option is set' { + set_git_aliases + alias expensiveCommands="git commit" + + run alias-finder -c "git commit -v" + + assert "${#lines[@]}" equals 3 + assert "${lines[1]}" same_as "gcv='git commit -v'" + assert "${lines[2]}" same_as "gc='git commit'" + assert "${lines[3]}" same_as "g=git" +} diff --git a/plugins/aliases/README.md b/plugins/aliases/README.md index bfb6ab8c4..14f9c5c53 100644 --- a/plugins/aliases/README.md +++ b/plugins/aliases/README.md @@ -15,8 +15,14 @@ Requirements: Python needs to be installed. ## Usage -- `acs`: show all aliases by group. +- `als`: show all aliases by group -- `acs `: filter aliases by `` and highlight. +- `als -h/--help`: print help message - ![screenshot](https://cloud.githubusercontent.com/assets/3602957/11581913/cb54fb8a-9a82-11e5-846b-5a67f67ad9ad.png) +- `als `: filter and highlight aliases by `` + +- `als -g /--group `: show only aliases for group ``. Multiple uses of the flag show all groups + +- `als --groups`: show only group names + + ![screenshot](https://github.com/ohmyzsh/ohmyzsh/assets/66907184/5bfa00ea-5fc3-4e97-8b22-2f74f6b948c7) diff --git a/plugins/aliases/aliases.plugin.zsh b/plugins/aliases/aliases.plugin.zsh index 9864de957..7f1ba83b8 100644 --- a/plugins/aliases/aliases.plugin.zsh +++ b/plugins/aliases/aliases.plugin.zsh @@ -4,7 +4,7 @@ 0="${${(M)0:#/*}:-$PWD/$0}" eval ' - function acs(){ + function als(){ (( $+commands[python3] )) || { echo "[error] No python executable detected" return diff --git a/plugins/aliases/cheatsheet.py b/plugins/aliases/cheatsheet.py index a7e3968b0..61bf5f956 100644 --- a/plugins/aliases/cheatsheet.py +++ b/plugins/aliases/cheatsheet.py @@ -2,6 +2,7 @@ import sys import itertools import termcolor +import argparse def parse(line): left = line[0:line.find('=')].strip() @@ -14,6 +15,7 @@ def parse(line): def cheatsheet(lines): exps = [ parse(line) for line in lines ] + exps.sort(key=lambda exp:exp[2]) cheatsheet = {'_default': []} for key, group in itertools.groupby(exps, lambda exp:exp[2]): group_list = [ item for item in group ] @@ -26,7 +28,7 @@ def cheatsheet(lines): target_aliases.extend(group_list) return cheatsheet -def pretty_print_group(key, aliases, highlight=None): +def pretty_print_group(key, aliases, highlight=None, only_groupname=False): if len(aliases) == 0: return group_hl_formatter = lambda g, hl: termcolor.colored(hl, 'yellow').join([termcolor.colored(part, 'red') for part in ('[%s]' % g).split(hl)]) @@ -35,21 +37,33 @@ def pretty_print_group(key, aliases, highlight=None): alias_formatter = lambda alias: termcolor.colored('\t%s = %s' % alias[0:2], 'green') if highlight and len(highlight)>0: print (group_hl_formatter(key, highlight)) - print ('\n'.join([alias_hl_formatter(alias, highlight) for alias in aliases])) + if not only_groupname: + print ('\n'.join([alias_hl_formatter(alias, highlight) for alias in aliases])) else: print (group_formatter(key)) - print ('\n'.join([alias_formatter(alias) for alias in aliases])) + if not only_groupname: + print ('\n'.join([alias_formatter(alias) for alias in aliases])) print ('') -def pretty_print(cheatsheet, wfilter): +def pretty_print(cheatsheet, wfilter, group_list=None, groups_only=False): sorted_key = sorted(cheatsheet.keys()) for key in sorted_key: + if group_list and key not in group_list: + continue aliases = cheatsheet.get(key) if not wfilter: - pretty_print_group(key, aliases, wfilter) + pretty_print_group(key, aliases, wfilter, groups_only) else: pretty_print_group(key, [ alias for alias in aliases if alias[0].find(wfilter)>-1 or alias[1].find(wfilter)>-1], wfilter) if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Pretty print aliases.", prog="als") + parser.add_argument('filter', nargs="*", metavar="", help="search aliases matching keywords") + parser.add_argument('-g', '--group', dest="group_list", action='append', help="only print aliases in given groups") + parser.add_argument('--groups', dest='groups_only', action='store_true', help="only print alias groups") + args = parser.parse_args() + lines = sys.stdin.readlines() - pretty_print(cheatsheet(lines), sys.argv[1] if len(sys.argv)>1 else None) + group_list = args.group_list or None + wfilter = " ".join(args.filter) or None + pretty_print(cheatsheet(lines), wfilter, group_list, args.groups_only) diff --git a/plugins/archlinux/README.md b/plugins/archlinux/README.md index fd772c61a..5e015dbaa 100644 --- a/plugins/archlinux/README.md +++ b/plugins/archlinux/README.md @@ -181,3 +181,4 @@ whether the package manager is installed, checked in the following order: - Ybalrid (Arthur Brainville) - ybalrid@ybalrid.info - Jeff M. Hubbard - jeffmhubbard@gmail.com - K. Harishankar(harishnkr) - hari2menon1234@gmail.com +- WH-2099 - wh2099@outlook.com \ No newline at end of file diff --git a/plugins/archlinux/archlinux.plugin.zsh b/plugins/archlinux/archlinux.plugin.zsh index 4f1364779..fca6548c0 100644 --- a/plugins/archlinux/archlinux.plugin.zsh +++ b/plugins/archlinux/archlinux.plugin.zsh @@ -23,30 +23,27 @@ alias pacfiles='pacman -F' alias pacls='pacman -Ql' alias pacown='pacman -Qo' alias pacupd="sudo pacman -Sy" -alias upgrade='sudo pacman -Syu' function paclist() { - # Based on https://bbs.archlinux.org/viewtopic.php?id=93683 - pacman -Qqe | \ - xargs -I '{}' \ - expac "${bold_color}% 20n ${fg_no_bold[white]}%d${reset_color}" '{}' + pacman -Qqe | xargs -I{} -P0 --no-run-if-empty pacman -Qs --color=auto "^{}\$" } function pacdisowned() { - local tmp db fs - tmp=${TMPDIR-/tmp}/pacman-disowned-$UID-$$ - db=$tmp/db - fs=$tmp/fs + local tmp_dir db fs + tmp_dir=$(mktemp --directory) + db=$tmp_dir/db + fs=$tmp_dir/fs - mkdir "$tmp" - trap 'rm -rf "$tmp"' EXIT + trap "rm -rf $tmp_dir" EXIT pacman -Qlq | sort -u > "$db" - find /bin /etc /lib /sbin /usr ! -name lost+found \ + find /etc /usr ! -name lost+found \ \( -type d -printf '%p/\n' -o -print \) | sort > "$fs" comm -23 "$fs" "$db" + + rm -rf $tmp_dir } alias pacmanallkeys='sudo pacman-key --refresh-keys' @@ -109,7 +106,6 @@ if (( $+commands[aura] )); then alias auupd="sudo aura -Sy" alias auupg='sudo sh -c "aura -Syu && aura -Au"' alias ausu='sudo sh -c "aura -Syu --no-confirm && aura -Au --no-confirm"' - alias upgrade='sudo aura -Syu' # extra bonus specially for aura alias auown="aura -Qqo" @@ -136,7 +132,6 @@ if (( $+commands[pacaur] )); then alias painsd='pacaur -S --asdeps' alias pamir='pacaur -Syy' alias paupd="pacaur -Sy" - alias upgrade='pacaur -Syu' fi if (( $+commands[trizen] )); then @@ -158,7 +153,6 @@ if (( $+commands[trizen] )); then alias trinsd='trizen -S --asdeps' alias trmir='trizen -Syy' alias trupd="trizen -Sy" - alias upgrade='trizen -Syu' fi if (( $+commands[yay] )); then @@ -180,5 +174,30 @@ if (( $+commands[yay] )); then alias yainsd='yay -S --asdeps' alias yamir='yay -Syy' alias yaupd="yay -Sy" - alias upgrade='yay -Syu' fi + +# Check Arch Linux PGP Keyring before System Upgrade to prevent failure. +function upgrade() { + echo ":: Checking Arch Linux PGP Keyring..." + local installedver="$(sudo pacman -Qi archlinux-keyring | grep -Po '(?<=Version : ).*')" + local currentver="$(sudo pacman -Si archlinux-keyring | grep -Po '(?<=Version : ).*')" + if [ $installedver != $currentver ]; then + echo " Arch Linux PGP Keyring is out of date." + echo " Updating before full system upgrade." + sudo pacman -Sy --needed --noconfirm archlinux-keyring + else + echo " Arch Linux PGP Keyring is up to date." + echo " Proceeding with full system upgrade." + fi + if (( $+commands[yay] )); then + yay -Syu + elif (( $+commands[trizen] )); then + trizen -Syu + elif (( $+commands[pacaur] )); then + pacaur -Syu + elif (( $+commands[aura] )); then + sudo aura -Syu + else + sudo pacman -Syu + fi +} diff --git a/plugins/argocd/README.md b/plugins/argocd/README.md new file mode 100644 index 000000000..0f900ff22 --- /dev/null +++ b/plugins/argocd/README.md @@ -0,0 +1,20 @@ +# Argo CD plugin + +This plugin adds completion for the [Argo CD](https://argoproj.github.io/cd/) CLI. + +To use it, add `argocd` to the plugins array in your zshrc file: + +```zsh +plugins=(... argocd) +``` + +This plugin does not add any aliases. + +## Cache + +This plugin caches the completion script and is automatically updated asynchronously when the plugin is +loaded, which is usually when you start up a new terminal emulator. + +The cache is stored at: + +- `$ZSH_CACHE/completions/_argocd` completions script diff --git a/plugins/argocd/argocd.plugin.zsh b/plugins/argocd/argocd.plugin.zsh new file mode 100644 index 000000000..8de7b0238 --- /dev/null +++ b/plugins/argocd/argocd.plugin.zsh @@ -0,0 +1,14 @@ +# Autocompletion for argocd. +if (( ! $+commands[argocd] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `argocd`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_argocd" ]]; then + typeset -g -A _comps + autoload -Uz _argocd + _comps[argocd]=_argocd +fi + +argocd completion zsh >| "$ZSH_CACHE_DIR/completions/_argocd" &| diff --git a/plugins/asdf/README.md b/plugins/asdf/README.md index e8aa976bc..f047860e2 100644 --- a/plugins/asdf/README.md +++ b/plugins/asdf/README.md @@ -6,22 +6,25 @@ Adds integration with [asdf](https://github.com/asdf-vm/asdf), the extendable ve ### Installation -1. Enable the plugin by adding it to your `plugins` definition in `~/.zshrc`. +1. [Download asdf](https://asdf-vm.com/guide/getting-started.html#_2-download-asdf) by running the following: + + ``` + git clone https://github.com/asdf-vm/asdf.git ~/.asdf + ``` + +2. [Enable asdf](https://asdf-vm.com/guide/getting-started.html#_3-install-asdf) by adding it to your `plugins` definition in `~/.zshrc`. ``` plugins=(asdf) ``` -2. [Install asdf](https://github.com/asdf-vm/asdf#setup) by running the following: - ``` - git clone https://github.com/asdf-vm/asdf.git ~/.asdf - ``` - ### Usage -See the [asdf usage documentation](https://github.com/asdf-vm/asdf#usage) for information on how to use asdf: +See the [asdf documentation](https://asdf-vm.com/guide/getting-started.html#_4-install-a-plugin) for information on how to use asdf: ``` -asdf plugin-add nodejs git@github.com:asdf-vm/asdf-nodejs.git -asdf install nodejs 5.9.1 +asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git +asdf install nodejs latest +asdf global nodejs latest +asdf local nodejs latest ``` diff --git a/plugins/asdf/asdf.plugin.zsh b/plugins/asdf/asdf.plugin.zsh index 3016282c6..7635d20c3 100644 --- a/plugins/asdf/asdf.plugin.zsh +++ b/plugins/asdf/asdf.plugin.zsh @@ -2,26 +2,29 @@ ASDF_DIR="${ASDF_DIR:-$HOME/.asdf}" ASDF_COMPLETIONS="$ASDF_DIR/completions" -# If not found, check for archlinux/AUR package (/opt/asdf-vm/) -if [[ ! -f "$ASDF_DIR/asdf.sh" || ! -f "$ASDF_COMPLETIONS/asdf.bash" ]] && [[ -f "/opt/asdf-vm/asdf.sh" ]]; then - ASDF_DIR="/opt/asdf-vm" - ASDF_COMPLETIONS="$ASDF_DIR" -fi - -# If not found, check for Homebrew package -if [[ ! -f "$ASDF_DIR/asdf.sh" || ! -f "$ASDF_COMPLETIONS/asdf.bash" ]] && (( $+commands[brew] )); then - brew_prefix="$(brew --prefix asdf)" - ASDF_DIR="${brew_prefix}/libexec" - ASDF_COMPLETIONS="${brew_prefix}/etc/bash_completion.d" - unset brew_prefix +if [[ ! -f "$ASDF_DIR/asdf.sh" || ! -f "$ASDF_COMPLETIONS/_asdf" ]]; then + # If not found, check for archlinux/AUR package (/opt/asdf-vm/) + if [[ -f "/opt/asdf-vm/asdf.sh" ]]; then + ASDF_DIR="/opt/asdf-vm" + ASDF_COMPLETIONS="$ASDF_DIR" + # If not found, check for Homebrew package + elif (( $+commands[brew] )); then + _ASDF_PREFIX="$(brew --prefix asdf)" + ASDF_DIR="${_ASDF_PREFIX}/libexec" + ASDF_COMPLETIONS="${_ASDF_PREFIX}/share/zsh/site-functions" + unset _ASDF_PREFIX + else + return + fi fi # Load command if [[ -f "$ASDF_DIR/asdf.sh" ]]; then - . "$ASDF_DIR/asdf.sh" - + source "$ASDF_DIR/asdf.sh" # Load completions - if [[ -f "$ASDF_COMPLETIONS/asdf.bash" ]]; then - . "$ASDF_COMPLETIONS/asdf.bash" + if [[ -f "$ASDF_COMPLETIONS/_asdf" ]]; then + fpath+=("$ASDF_COMPLETIONS") + autoload -Uz _asdf + compdef _asdf asdf # compdef is already loaded before loading plugins fi fi diff --git a/plugins/autoenv/autoenv.plugin.zsh b/plugins/autoenv/autoenv.plugin.zsh index 229a8a834..2f84f0acf 100644 --- a/plugins/autoenv/autoenv.plugin.zsh +++ b/plugins/autoenv/autoenv.plugin.zsh @@ -17,9 +17,13 @@ if ! type autoenv_init >/dev/null; then /usr/local/bin /usr/share/autoenv-git ~/Library/Python/bin + .venv/bin + venv/bin + env/bin + .env/bin ) for d ( $install_locations ); do - if [[ -e $d/activate.sh ]]; then + if [[ -e $d/activate || -e $d/activate.sh ]]; then autoenv_dir=$d break fi @@ -29,13 +33,13 @@ if ! type autoenv_init >/dev/null; then # Look for Homebrew path as a last resort if [[ -z "$autoenv_dir" ]] && (( $+commands[brew] )); then d=$(brew --prefix)/opt/autoenv - if [[ -e $d/activate.sh ]]; then + if [[ -e $d/activate || -e $d/activate.sh ]]; then autoenv_dir=$d fi fi # Complain if autoenv is not installed - if [[ -z $autoenv_dir ]]; then + if [[ -z $autoenv_dir ]]; then cat <&2 -------- AUTOENV --------- Could not locate autoenv installation. @@ -46,7 +50,11 @@ END return 1 fi # Load autoenv - source $autoenv_dir/activate.sh + if [[ -e $autoenv_dir/activate ]]; then + source $autoenv_dir/activate + else + source $autoenv_dir/activate.sh + fi fi } [[ $? != 0 ]] && return $? diff --git a/plugins/autojump/autojump.plugin.zsh b/plugins/autojump/autojump.plugin.zsh index 8593353b2..1b868ee8d 100644 --- a/plugins/autojump/autojump.plugin.zsh +++ b/plugins/autojump/autojump.plugin.zsh @@ -1,17 +1,18 @@ declare -a autojump_paths autojump_paths=( - $HOME/.autojump/etc/profile.d/autojump.zsh # manual installation - $HOME/.autojump/share/autojump/autojump.zsh # manual installation - $HOME/.nix-profile/etc/profile.d/autojump.sh # NixOS installation - /run/current-system/sw/share/autojump/autojump.zsh # NixOS installation - /usr/share/autojump/autojump.zsh # Debian and Ubuntu package - /etc/profile.d/autojump.zsh # manual installation - /etc/profile.d/autojump.sh # Gentoo installation - /usr/local/share/autojump/autojump.zsh # FreeBSD installation - /usr/pkg/share/autojump/autojump.zsh # NetBSD installation - /opt/local/etc/profile.d/autojump.sh # macOS with MacPorts - /usr/local/etc/profile.d/autojump.sh # macOS with Homebrew (default) - /opt/homebrew/etc/profile.d/autojump.sh # macOS with Homebrew (default on M1 macs) + $HOME/.autojump/etc/profile.d/autojump.zsh # manual installation + $HOME/.autojump/share/autojump/autojump.zsh # manual installation + $HOME/.nix-profile/etc/profile.d/autojump.sh # NixOS installation + /run/current-system/sw/share/autojump/autojump.zsh # NixOS installation + /usr/share/autojump/autojump.zsh # Debian and Ubuntu package + /etc/profile.d/autojump.zsh # manual installation + /etc/profile.d/autojump.sh # Gentoo installation + /usr/local/share/autojump/autojump.zsh # FreeBSD installation + /usr/pkg/share/autojump/autojump.zsh # NetBSD installation + /opt/local/etc/profile.d/autojump.sh # macOS with MacPorts + /usr/local/etc/profile.d/autojump.sh # macOS with Homebrew (default) + /opt/homebrew/etc/profile.d/autojump.sh # macOS with Homebrew (default on M1 macs) + /etc/profiles/per-user/$USER/etc/profile.d/autojump.sh # macOS Nix, Home Manager and flakes ) for file in $autojump_paths; do diff --git a/plugins/aws/README.md b/plugins/aws/README.md index d6f4f4600..dbf8dcfeb 100644 --- a/plugins/aws/README.md +++ b/plugins/aws/README.md @@ -1,7 +1,8 @@ # aws -This plugin provides completion support for [awscli](https://docs.aws.amazon.com/cli/latest/reference/index.html) -and a few utilities to manage AWS profiles and display them in the prompt. +This plugin provides completion support for [awscli v2](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/index.html) +and a few utilities to manage AWS profiles/regions and display them in the prompt. +[awscli v1](https://docs.aws.amazon.com/cli/latest/userguide/cliv2-migration.html) is no longer supported. To use it, add `aws` to the plugins array in your zshrc file. @@ -12,9 +13,14 @@ plugins=(... aws) ## Plugin commands * `asp []`: sets `$AWS_PROFILE` and `$AWS_DEFAULT_PROFILE` (legacy) to ``. - It also sets `$AWS_EB_PROFILE` to `` for the Elastic Beanstalk CLI. + It also sets `$AWS_EB_PROFILE` to `` for the Elastic Beanstalk CLI. It sets `$AWS_PROFILE_REGION` for display in `aws_prompt_info`. Run `asp` without arguments to clear the profile. -* `asp [] login`: If AWS SSO has been configured in your aws profile, it will run the `aws sso login` command following profile selection. +* `asp [] login`: If AWS SSO has been configured in your aws profile, it will run the `aws sso login` command following profile selection. +* `asp [] login []`: In addition to `asp [] login`, if SSO session has been configured in your aws profile, it will run the `aws sso login --sso-session ` command following profile selection. +* `asp [] logout`: If AWS SSO has been configured in your aws profile, it will run the `aws sso logout` command following profile selection. + +* `asr []`: sets `$AWS_REGION` and `$AWS_DEFAULT_REGION` (legacy) to ``. + Run `asr` without arguments to clear the profile. * `acp [] []`: in addition to `asp` functionality, it actually changes the profile by assuming the role specified in the `` configuration. It supports @@ -25,25 +31,36 @@ plugins=(... aws) * `agp`: gets the current value of `$AWS_PROFILE`. +* `agr`: gets the current value of `$AWS_REGION`. + * `aws_change_access_key`: changes the AWS access key of a profile. * `aws_profiles`: lists the available profiles in the `$AWS_CONFIG_FILE` (default: `~/.aws/config`). Used to provide completion for the `asp` function. +* `aws_regions`: lists the available regions. + Used to provide completion for the `asr` function. + ## Plugin options * Set `SHOW_AWS_PROMPT=false` in your zshrc file if you want to prevent the plugin from modifying your RPROMPT. Some themes might overwrite the value of RPROMPT instead of appending to it, so they'll need to be fixed to - see the AWS profile prompt. + see the AWS profile/region prompt. ## Theme The plugin creates an `aws_prompt_info` function that you can use in your theme, which displays -the current `$AWS_PROFILE`. It uses two variables to control how that is shown: +the current `$AWS_PROFILE` and `$AWS_REGION`. It uses four variables to control how that is shown: -* ZSH_THEME_AWS_PREFIX: sets the prefix of the AWS_PROFILE. Defaults to ``. +* ZSH_THEME_AWS_PROFILE_SUFFIX: sets the suffix of the AWS_PROFILE. Defaults to `>`. + +* ZSH_THEME_AWS_REGION_PREFIX: sets the prefix of the AWS_REGION. Defaults to ``. + +* ZSH_THEME_AWS_DIVIDER: sets the divider between ZSH_THEME_AWS_PROFILE_SUFFIX and ZSH_THEME_AWS_REGION_PREFIX. Defaults to ` ` (single space). ## Configuration @@ -53,7 +70,7 @@ the current `$AWS_PROFILE`. It uses two variables to control how that is shown: Source profile credentials in `~/.aws/credentials`: -``` +```ini [source-profile-name] aws_access_key_id = ... aws_secret_access_key = ... @@ -61,7 +78,7 @@ aws_secret_access_key = ... Role configuration in `~/.aws/config`: -``` +```ini [profile source-profile-name] mfa_serial = arn:aws:iam::111111111111:mfa/myuser region = us-east-1 diff --git a/plugins/aws/aws.plugin.zsh b/plugins/aws/aws.plugin.zsh index 2167f552c..fd00714e7 100644 --- a/plugins/aws/aws.plugin.zsh +++ b/plugins/aws/aws.plugin.zsh @@ -2,10 +2,14 @@ function agp() { echo $AWS_PROFILE } +function agr() { + echo $AWS_REGION +} + # AWS profile selection function asp() { if [[ -z "$1" ]]; then - unset AWS_DEFAULT_PROFILE AWS_PROFILE AWS_EB_PROFILE + unset AWS_DEFAULT_PROFILE AWS_PROFILE AWS_EB_PROFILE AWS_PROFILE_REGION echo AWS profile cleared. return fi @@ -22,11 +26,38 @@ function asp() { export AWS_PROFILE=$1 export AWS_EB_PROFILE=$1 + export AWS_PROFILE_REGION=$(aws configure get region) + if [[ "$2" == "login" ]]; then - aws sso login + if [[ -n "$3" ]]; then + aws sso login --sso-session $3 + else + aws sso login + fi + elif [[ "$2" == "logout" ]]; then + aws sso logout fi } +# AWS region selection +function asr() { + if [[ -z "$1" ]]; then + unset AWS_DEFAULT_REGION AWS_REGION + echo AWS region cleared. + return + fi + + local -a available_regions + available_regions=($(aws_regions)) + if [[ -z "${available_regions[(r)$1]}" ]]; then + echo "${fg[red]}Available regions: \n$(aws_regions)" + return 1 + fi + + export AWS_REGION=$1 + export AWS_DEFAULT_REGION=$1 +} + # AWS profile switch function acp() { if [[ -z "$1" ]]; then @@ -135,21 +166,60 @@ function aws_change_access_key() { return 1 fi - echo "Insert the credentials when asked." - asp "$1" || return 1 - AWS_PAGER="" aws iam create-access-key - AWS_PAGER="" aws configure --profile "$1" + local profile="$1" + # Get current access key + local original_aws_access_key_id="$(aws configure get aws_access_key_id --profile $profile)" - echo "You can now safely delete the old access key running \`aws iam delete-access-key --access-key-id ID\`" + asp "$profile" || return 1 + echo "Generating a new access key pair for you now." + if aws --no-cli-pager iam create-access-key; then + echo "Insert the newly generated credentials when asked." + aws --no-cli-pager configure --profile $profile + else + echo "Current access keys:" + aws --no-cli-pager iam list-access-keys + echo "Profile \"${profile}\" is currently using the $original_aws_access_key_id key. You can delete an old access key by running \`aws --profile $profile iam delete-access-key --access-key-id AccessKeyId\`" + return 1 + fi + + read -q "yn?Would you like to disable your previous access key (${original_aws_access_key_id}) now? " + case $yn in + [Yy]*) + echo -n "\nDisabling access key ${original_aws_access_key_id}..." + if aws --no-cli-pager iam update-access-key --access-key-id ${original_aws_access_key_id} --status Inactive; then + echo "done." + else + echo "\nFailed to disable ${original_aws_access_key_id} key." + fi + ;; + *) + echo "" + ;; + esac + echo "You can now safely delete the old access key by running \`aws --profile $profile iam delete-access-key --access-key-id ${original_aws_access_key_id}\`" echo "Your current keys are:" - AWS_PAGER="" aws iam list-access-keys + aws --no-cli-pager iam list-access-keys +} + +function aws_regions() { + if [[ $AWS_DEFAULT_PROFILE || $AWS_PROFILE ]];then + aws ec2 describe-regions |grep RegionName | awk -F ':' '{gsub(/"/, "", $2);gsub(/,/, "", $2);gsub(/ /, "", $2); print $2}' + else + echo "You must specify a AWS profile." + fi } function aws_profiles() { + aws --no-cli-pager configure list-profiles 2> /dev/null && return [[ -r "${AWS_CONFIG_FILE:-$HOME/.aws/config}" ]] || return 1 grep --color=never -Eo '\[.*\]' "${AWS_CONFIG_FILE:-$HOME/.aws/config}" | sed -E 's/^[[:space:]]*\[(profile)?[[:space:]]*([^[:space:]]+)\][[:space:]]*$/\2/g' } +function _aws_regions() { + reply=($(aws_regions)) +} +compctl -K _aws_regions asr + function _aws_profiles() { reply=($(aws_profiles)) } @@ -157,15 +227,25 @@ compctl -K _aws_profiles asp acp aws_change_access_key # AWS prompt function aws_prompt_info() { - [[ -n "$AWS_PROFILE" ]] || return - echo "${ZSH_THEME_AWS_PREFIX=}" + local _aws_to_show + local region="${AWS_REGION:-${AWS_DEFAULT_REGION:-$AWS_PROFILE_REGION}}" + + if [[ -n "$AWS_PROFILE" ]];then + _aws_to_show+="${ZSH_THEME_AWS_PROFILE_PREFIX=""}" + fi + + if [[ -n "$region" ]]; then + [[ -n "$_aws_to_show" ]] && _aws_to_show+="${ZSH_THEME_AWS_DIVIDER=" "}" + _aws_to_show+="${ZSH_THEME_AWS_REGION_PREFIX=""}" + fi + + echo "$_aws_to_show" } if [[ "$SHOW_AWS_PROMPT" != false && "$RPROMPT" != *'$(aws_prompt_info)'* ]]; then RPROMPT='$(aws_prompt_info)'"$RPROMPT" fi - # Load awscli completions # AWS CLI v2 comes with its own autocompletion. Check if that is there, otherwise fall back @@ -210,3 +290,4 @@ else [[ -r $_aws_zsh_completer_path ]] && source $_aws_zsh_completer_path unset _aws_zsh_completer_path _brew_prefix fi + diff --git a/plugins/azure/README.md b/plugins/azure/README.md new file mode 100644 index 000000000..f39930851 --- /dev/null +++ b/plugins/azure/README.md @@ -0,0 +1,49 @@ +# azure + +This plugin provides completion support for [azure cli](https://docs.microsoft.com/en-us/cli/azure/) +and a few utilities to manage azure subscriptions and display them in the prompt. + +To use it, add `azure` to the plugins array in your zshrc file. + +```zsh +plugins=(... azure) +``` + +## Plugin commands + + +* `az_subscriptions`: lists the available subscriptions in the `AZURE_CONFIG_DIR` (default: `~/.azure/`). + Used to provide completion for the `azss` function. + +* `azgs`: gets the current value of `$azure_subscription`. + +* `azss []`: sets the `$azure_subscription`. + + +NOTE : because azure keeps the state of active subscription in ${AZURE_CONFIG_DIR:-$HOME/.azure/azureProfile.json}, the prompt command requires `jq` to be enabled to parse the file. If jq is not in the path the prompt will show nothing + +## Theme + +The plugin creates an `azure_prompt_info` function that you can use in your theme, which displays +the current `$azure_subscription`. It uses two variables to control how that is shown: + +- ZSH_THEME_AZURE_PREFIX: sets the prefix of the azure_subscription. Defaults to ``. + + +``` +RPROMPT='$(azure_prompt_info)' +``` + +## Develop + +On ubuntu get a working environment with : + +` docker run -it -v $(pwd):/mnt -w /mnt ubuntu bash` + +``` +apt install -y curl jq zsh git vim +sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" +curl -sL https://aka.ms/InstallAzureCLIDeb | bash +``` \ No newline at end of file diff --git a/plugins/azure/azure.plugin.zsh b/plugins/azure/azure.plugin.zsh new file mode 100644 index 000000000..b33b0f805 --- /dev/null +++ b/plugins/azure/azure.plugin.zsh @@ -0,0 +1,60 @@ +# AZ Get Subscriptions +function azgs() { + az account show --output tsv --query 'name' 2>/dev/null +} + +# AZ Subscription Selection +alias azss="az account set --subscription" + + +function az_subscriptions() { + az account list --all --output tsv --query '[*].name' 2> /dev/null +} + +function _az_subscriptions() { + reply=($(az_subscriptions)) +} +compctl -K _az_subscriptions azss + +# Azure prompt +function azure_prompt_info() { + [[ ! -f "${AZURE_CONFIG_DIR:-$HOME/.azure}/azureProfile.json" ]] && return + # azgs is too expensive, if we have jq, we enable the prompt + (( $+commands[jq] )) || return 1 + azgs=$(jq -r '.subscriptions[] | select(.isDefault==true) .name' "${AZURE_CONFIG_DIR:-$HOME/.azure}/azureProfile.json") + echo "${ZSH_THEME_AZURE_PREFIX:=}" +} + + +# Load az completions +function _az-homebrew-installed() { + # check if Homebrew is installed + (( $+commands[brew] )) || return 1 + + # if so, we assume it's default way to install brew + if [[ ${commands[brew]:t2} == bin/brew ]]; then + _brew_prefix="${commands[brew]:h:h}" # remove trailing /bin/brew + else + # ok, it is not in the default prefix + # this call to brew is expensive (about 400 ms), so at least let's make it only once + _brew_prefix=$(brew --prefix) + fi +} + + +# get az.completion.sh location from $PATH +_az_zsh_completer_path="$commands[az_zsh_completer.sh]" + +# otherwise check common locations +if [[ -z $_az_zsh_completer_path ]]; then + # Homebrew + if _az-homebrew-installed; then + _az_zsh_completer_path=$_brew_prefix/etc/bash_completion.d/az + # Linux + else + _az_zsh_completer_path=/etc/bash_completion.d/azure-cli + fi +fi + +[[ -r $_az_zsh_completer_path ]] && autoload -U +X bashcompinit && bashcompinit && source $_az_zsh_completer_path +unset _az_zsh_completer_path _brew_prefix diff --git a/plugins/battery/battery.plugin.zsh b/plugins/battery/battery.plugin.zsh index db5eeb93a..1d3d529a3 100644 --- a/plugins/battery/battery.plugin.zsh +++ b/plugins/battery/battery.plugin.zsh @@ -13,6 +13,10 @@ # Author: Avneet Singh (kalsi-avneet) # # Modified to add support for Android # ########################################### +# Author: Not Pua (im-notpua) # +# Modified to add support for OpenBSD # +########################################### + if [[ "$OSTYPE" = darwin* ]]; then function battery_is_charging() { @@ -139,6 +143,46 @@ elif [[ "$OSTYPE" = linux-android ]] && (( ${+commands[termux-battery-status]} ) echo "%{$fg[$color]%}${battery_pct}%%%{$reset_color%}" fi } +elif [[ "$OSTYPE" = openbsd* ]]; then + function battery_is_charging() { + [[ $(apm -b) -eq 3 ]] + } + function battery_pct() { + apm -l + } + function battery_pct_remaining() { + if ! battery_is_charging; then + battery_pct + else + echo "External Power" + fi + } + function battery_time_remaining() { + local remaining_time + remaining_time=$(apm -m) + if [[ $remaining_time -ge 0 ]]; then + ((hour = $remaining_time / 60 )) + ((minute = $remaining_time % 60 )) + printf %02d:%02d $hour $minute + fi + } + function battery_pct_prompt() { + local battery_pct color + battery_pct=$(battery_pct_remaining) + if battery_is_charging; then + echo "∞" + else + if [[ $battery_pct -gt 50 ]]; then + color='green' + elif [[ $battery_pct -gt 20 ]]; then + color='yellow' + else + color='red' + fi + echo "%{$fg[$color]%}${battery_pct}%%%{$reset_color%}" + fi + } + elif [[ "$OSTYPE" = linux* ]]; then function battery_is_charging() { if (( $+commands[acpitool] )); then diff --git a/plugins/bazel/_bazel b/plugins/bazel/_bazel index c34c572b0..ea1f4cace 100644 --- a/plugins/bazel/_bazel +++ b/plugins/bazel/_bazel @@ -1,4 +1,4 @@ -#compdef bazel +#compdef bazel bazelisk # Copyright 2015 The Bazel Authors. All rights reserved. # diff --git a/plugins/bgnotify/README.md b/plugins/bgnotify/README.md index 1d8fac54d..33d529f15 100644 --- a/plugins/bgnotify/README.md +++ b/plugins/bgnotify/README.md @@ -1,19 +1,19 @@ # bgnotify zsh plugin -cross-platform background notifications for long running commands! Supports OSX and Ubuntu linux. +cross-platform background notifications for long running commands! Supports OSX and Linux. Standalone homepage: [t413/zsh-background-notify](https://github.com/t413/zsh-background-notify) ----------------------------------- +--- -## How to use! +## How to use Just add bgnotify to your plugins list in your `.zshrc` - On OS X you'll need [terminal-notifier](https://github.com/alloy/terminal-notifier) * `brew install terminal-notifier` (or `gem install terminal-notifier`) -- On ubuntu you're already all set! -- On windows you can use [notifu](https://www.paralint.com/projects/notifu/) or the Cygwin Ports libnotify package +- On Linux, make sure you have `notify-send` or `kdialog` installed. If you're using Ubuntu you should already be all set! +- On Windows you can use [notifu](https://www.paralint.com/projects/notifu/) or the Cygwin Ports libnotify package ## Screenshots @@ -35,20 +35,29 @@ Just add bgnotify to your plugins list in your `.zshrc` One can configure a few things: +- `bgnotify_bell` enabled or disables the terminal bell (default true) - `bgnotify_threshold` sets the notification threshold time (default 6 seconds) -- `function bgnotify_formatted` lets you change the notification +- `function bgnotify_formatted` lets you change the notification. You can for instance customize the message and pass in an icon. Use these by adding a function definition before the your call to source. Example: -~~~ sh +```sh +bgnotify_bell=false ## disable terminal bell bgnotify_threshold=4 ## set your own notification threshold function bgnotify_formatted { ## $1=exit_status, $2=command, $3=elapsed_time - [ $1 -eq 0 ] && title="Holy Smokes Batman!" || title="Holy Graf Zeppelin!" - bgnotify "$title -- after $3 s" "$2"; + + # Humanly readable elapsed time + local elapsed="$(( $3 % 60 ))s" + (( $3 < 60 )) || elapsed="$((( $3 % 3600) / 60 ))m $elapsed" + (( $3 < 3600 )) || elapsed="$(( $3 / 3600 ))h $elapsed" + + [ $1 -eq 0 ] && title="Holy Smokes Batman" || title="Holy Graf Zeppelin" + [ $1 -eq 0 ] && icon="$HOME/icons/success.png" || icon="$HOME/icons/fail.png" + bgnotify "$title - took ${elapsed}" "$2" "$icon" } plugins=(git bgnotify) ## add to plugins list source $ZSH/oh-my-zsh.sh ## existing source call -~~~ +``` diff --git a/plugins/bgnotify/bgnotify.plugin.zsh b/plugins/bgnotify/bgnotify.plugin.zsh index 479796dbe..0e3f2c640 100644 --- a/plugins/bgnotify/bgnotify.plugin.zsh +++ b/plugins/bgnotify/bgnotify.plugin.zsh @@ -1,93 +1,141 @@ #!/usr/bin/env zsh -## setup ## +## Setup -[[ -o interactive ]] || return #interactive only! -zmodload zsh/datetime || { print "can't load zsh/datetime"; return } # faster than date() -autoload -Uz add-zsh-hook || { print "can't add zsh hook!"; return } +[[ -o interactive ]] || return # don't load on non-interactive shells +[[ -z "$SSH_CLIENT" && -z "$SSH_TTY" ]] || return # don't load on a SSH connection -(( ${+bgnotify_threshold} )) || bgnotify_threshold=5 #default 10 seconds +zmodload zsh/datetime # faster than `date` -## definitions ## +## Zsh Hooks -if ! (type bgnotify_formatted | grep -q 'function'); then ## allow custom function override - function bgnotify_formatted { ## args: (exit_status, command, elapsed_seconds) - elapsed="$(( $3 % 60 ))s" - (( $3 >= 60 )) && elapsed="$((( $3 % 3600) / 60 ))m $elapsed" - (( $3 >= 3600 )) && elapsed="$(( $3 / 3600 ))h $elapsed" - [ $1 -eq 0 ] && bgnotify "#win (took $elapsed)" "$2" || bgnotify "#fail (took $elapsed)" "$2" - } -fi - -currentAppId () { - if (( $+commands[osascript] )); then - osascript -e 'tell application (path to frontmost application as text) to id' 2>/dev/null - fi -} - -currentWindowId () { - if hash osascript 2>/dev/null; then #osx - osascript -e 'tell application (path to frontmost application as text) to id of front window' 2&> /dev/null || echo "0" - elif (hash notify-send 2>/dev/null || hash kdialog 2>/dev/null); then #ubuntu! - xprop -root 2> /dev/null | awk '/NET_ACTIVE_WINDOW/{print $5;exit} END{exit !$5}' || echo "0" - else - echo $EPOCHSECONDS #fallback for windows - fi -} - -bgnotify () { ## args: (title, subtitle) - if hash terminal-notifier 2>/dev/null; then #osx - local term_id="$bgnotify_appid" - if [[ -z "$term_id" ]]; then - case "$TERM_PROGRAM" in - iTerm.app) term_id='com.googlecode.iterm2' ;; - Apple_Terminal) term_id='com.apple.terminal' ;; - esac - fi - - ## now call terminal-notifier, (hopefully with $term_id!) - if [[ -z "$term_id" ]]; then - terminal-notifier -message "$2" -title "$1" >/dev/null - else - terminal-notifier -message "$2" -title "$1" -activate "$term_id" -sender "$term_id" >/dev/null - fi - elif hash growlnotify 2>/dev/null; then #osx growl - growlnotify -m "$1" "$2" - elif hash notify-send 2>/dev/null; then #ubuntu gnome! - notify-send "$1" "$2" - elif hash kdialog 2>/dev/null; then #ubuntu kde! - kdialog --title "$1" --passivepopup "$2" 5 - elif hash notifu 2>/dev/null; then #cygwyn support! - notifu /m "$2" /p "$1" - fi -} - - -## Zsh hooks ## - -bgnotify_begin() { +function bgnotify_begin { bgnotify_timestamp=$EPOCHSECONDS bgnotify_lastcmd="${1:-$2}" - bgnotify_appid="$(currentAppId)" - bgnotify_windowid=$(currentWindowId) } -bgnotify_end() { - didexit=$? - elapsed=$(( EPOCHSECONDS - bgnotify_timestamp )) - past_threshold=$(( elapsed >= bgnotify_threshold )) - if (( bgnotify_timestamp > 0 )) && (( past_threshold )); then - if [[ $(currentAppId) != "$bgnotify_appid" || $(currentWindowId) != "$bgnotify_windowid" ]]; then - print -n "\a" - bgnotify_formatted "$didexit" "$bgnotify_lastcmd" "$elapsed" - fi +function bgnotify_end { + { + local exit_status=$? + local elapsed=$(( EPOCHSECONDS - bgnotify_timestamp )) + + # check time elapsed + [[ $bgnotify_timestamp -gt 0 ]] || return 0 + [[ $elapsed -ge $bgnotify_threshold ]] || return 0 + + # check if Terminal app is not active + [[ $(bgnotify_appid) != "$bgnotify_termid" ]] || return 0 + + bgnotify_formatted "$exit_status" "$bgnotify_lastcmd" "$elapsed" + } always { + bgnotify_timestamp=0 + } +} + +autoload -Uz add-zsh-hook +add-zsh-hook preexec bgnotify_begin +add-zsh-hook precmd bgnotify_end + + +## Functions + +# allow custom function override +(( ${+functions[bgnotify_formatted]} )) || \ +function bgnotify_formatted { + local exit_status=$1 + local cmd="$2" + + # humanly readable elapsed time + local elapsed="$(( $3 % 60 ))s" + (( $3 < 60 )) || elapsed="$((( $3 % 3600) / 60 ))m $elapsed" + (( $3 < 3600 )) || elapsed="$(( $3 / 3600 ))h $elapsed" + + [[ $bgnotify_bell = true ]] && printf '\a' # beep sound + if [[ $exit_status -eq 0 ]]; then + bgnotify "#win (took $elapsed)" "$cmd" + else + bgnotify "#fail (took $elapsed)" "$cmd" fi - bgnotify_timestamp=0 #reset it to 0! } -## only enable if a local (non-ssh) connection -if [ -z "$SSH_CLIENT" ] && [ -z "$SSH_TTY" ]; then - add-zsh-hook preexec bgnotify_begin - add-zsh-hook precmd bgnotify_end -fi +function bgnotify_appid { + if (( ${+commands[osascript]} )); then + osascript -e "tell application id \"$(bgnotify_programid)\" to get the {id, frontmost, id of front window, visible of front window}" 2>/dev/null + elif [[ -n $WAYLAND_DISPLAY ]] && (( ${+commands[swaymsg]} )); then # wayland+sway + local app_id=$(bgnotify_find_sway_appid) + [[ -n "$app_id" ]] && echo "$app_id" || echo $EPOCHSECONDS + elif [[ -z $WAYLAND_DISPLAY ]] && [[ -n $DISPLAY ]] && (( ${+commands[xprop]} )); then + xprop -root _NET_ACTIVE_WINDOW 2>/dev/null | cut -d' ' -f5 + else + echo $EPOCHSECONDS + fi +} + + +function bgnotify_find_sway_appid { + # output is "app_id,container_id", for example "Alacritty,1694" + # see example swaymsg output: https://github.com/ohmyzsh/ohmyzsh/files/13463939/output.json + if (( ${+commands[jq]} )); then + swaymsg -t get_tree | jq '.. | select(.type?) | select(.focused==true) | {app_id, id} | join(",")' + else + swaymsg -t get_tree | awk ' + BEGIN { Id = ""; Appid = ""; FocusNesting = -1; Nesting = 0 } + { + # Enter a block + if ($0 ~ /.*{$/) Nesting++ + + # Exit a block. If Nesting is now less than FocusNesting, we have the data we are looking for + if ($0 ~ /^[[:blank:]]*}.*/) { Nesting--; if (FocusNesting > 0 && Nesting < FocusNesting) exit 0 } + + # Save the Id, it is potentially what we are looking for + if ($0 ~ /^[[:blank:]]*"id": [0-9]*,?$/) { sub(/^[[:blank:]]*"id": /, ""); sub(/,$/, ""); Id = $0 } + + # Save the Appid, it is potentially what we are looking for + if ($0 ~ /^[[:blank:]]*"app_id": ".*",?$/) { sub(/^[[:blank:]]*"app_id": "/, ""); sub(/",$/, ""); Appid = $0 } + + # Window is focused, this nesting block contains the Id and Appid we want! + if ($0 ~ /^[[:blank:]]*"focused": true,?$/) { FocusNesting = Nesting } + } + END { + if (Appid != "" && Id != "" && FocusNesting != -1) print Appid "," Id + else print "" + }' + fi +} + +function bgnotify_programid { + case "$TERM_PROGRAM" in + iTerm.app) echo 'com.googlecode.iterm2' ;; + Apple_Terminal) echo 'com.apple.terminal' ;; + esac +} + +function bgnotify { + local title="$1" + local message="$2" + local icon="$3" + if (( ${+commands[terminal-notifier]} )); then # macOS + local term_id=$(bgnotify_programid) + terminal-notifier -message "$message" -title "$title" ${=icon:+-appIcon "$icon"} ${=term_id:+-activate "$term_id" -sender "$term_id"} &>/dev/null + elif (( ${+commands[growlnotify]} )); then # macOS growl + growlnotify -m "$title" "$message" + elif (( ${+commands[notify-send]} )); then + notify-send "$title" "$message" ${=icon:+--icon "$icon"} + elif (( ${+commands[kdialog]} )); then # KDE + kdialog --title "$title" --passivepopup "$message" 5 + elif (( ${+commands[notifu]} )); then # cygwin + notifu /m "$message" /p "$title" ${=icon:+/i "$icon"} + fi +} + +## Defaults + +# enable terminal bell on notify by default +bgnotify_bell=${bgnotify_bell:-true} + +# notify if command took longer than 5s by default +bgnotify_threshold=${bgnotify_threshold:-5} + +# bgnotify_appid is slow in macOS and the terminal ID won't change, so cache it at startup +bgnotify_termid="$(bgnotify_appid)" diff --git a/plugins/brew/README.md b/plugins/brew/README.md index 64e0e1153..299393b28 100644 --- a/plugins/brew/README.md +++ b/plugins/brew/README.md @@ -10,25 +10,34 @@ plugins=(... brew) ## Shellenv -This plugin also executes `brew shellenv` at plugin load to set up many useful variables, such as `HOMEBREW_PREFIX` or `HOMEBREW_REPOSITORY`. +If `brew` is not found in the PATH, this plugin will attempt to find it in common locations, and execute +`brew shellenv` to set the environment appropriately. This plugin will also export +`HOMEBREW_PREFIX="$(brew --prefix)"` if not previously defined for convenience. + +In case you installed `brew` in a non-common location, you can still set `BREW_LOCATION` variable pointing to +the `brew` binary before sourcing `oh-my-zsh.sh` and it'll set up the environment. ## Aliases -| Alias | Command | Description | -| -------- | ------------------------------------- | ------------------------------------------------------------------- | -| `bcubc` | `brew upgrade --cask && brew cleanup` | Update outdated casks, then run cleanup. | -| `bcubo` | `brew update && brew outdated --cask` | Update Homebrew data, then list outdated casks. | -| `brewp` | `brew pin` | Pin a specified formula so that it's not upgraded. | -| `brews` | `brew list -1` | List installed formulae or the installed files for a given formula. | -| `brewsp` | `brew list --pinned` | List pinned formulae, or show the version of a given formula. | -| `bubc` | `brew upgrade && brew cleanup` | Upgrade outdated formulae and casks, then run cleanup. | -| `bubo` | `brew update && brew outdated` | Update Homebrew data, then list outdated formulae and casks. | -| `bubu` | `bubo && bubc` | Do the last two operations above. | -| `buf` | `brew upgrade --formula` | Upgrade only formulas (not casks). | +| Alias | Command | Description | +| -------- | --------------------------------------- | ------------------------------------------------------------------- | +| `bcubc` | `brew upgrade --cask && brew cleanup` | Update outdated casks, then run cleanup. | +| `bcubo` | `brew update && brew outdated --cask` | Update Homebrew data, then list outdated casks. | +| `brewp` | `brew pin` | Pin a specified formula so that it's not upgraded. | +| `brews` | `brew list -1` | List installed formulae or the installed files for a given formula. | +| `brewsp` | `brew list --pinned` | List pinned formulae, or show the version of a given formula. | +| `bubc` | `brew upgrade && brew cleanup` | Upgrade outdated formulae and casks, then run cleanup. | +| `bugbc` | `brew upgrade --greedy && brew cleanup` | Upgrade outdated formulae and casks (greedy), then run cleanup. | +| `bubo` | `brew update && brew outdated` | Update Homebrew data, then list outdated formulae and casks. | +| `bubu` | `bubo && bubc` | Do the last two operations above. | +| `bfu` | `brew upgrade --formula` | Upgrade only formulas (not casks). | +| `buz` | `brew uninstall --zap` | Remove all files associated with a cask. | ## Completion -With the release of Homebrew 1.0, they decided to bundle the zsh completion as part of the -brew installation, so we no longer ship it with the brew plugin; now it only has brew -aliases. If you find that brew completion no longer works, make sure you have your Homebrew -installation fully up to date. +This plugin configures paths with Homebrew's completion functions automatically, so you don't need to do it +manually. See: https://docs.brew.sh/Shell-Completion#configuring-completions-in-zsh. + +With the release of Homebrew 1.0, they decided to bundle the zsh completion as part of the brew installation, +so we no longer ship it with the brew plugin; now it only has brew aliases. If you find that brew completion +no longer works, make sure you have your Homebrew installation fully up to date. diff --git a/plugins/brew/brew.plugin.zsh b/plugins/brew/brew.plugin.zsh index 4a2322216..447036376 100644 --- a/plugins/brew/brew.plugin.zsh +++ b/plugins/brew/brew.plugin.zsh @@ -1,5 +1,10 @@ if (( ! $+commands[brew] )); then - if [[ -x /opt/homebrew/bin/brew ]]; then + if [[ -n "$BREW_LOCATION" ]]; then + if [[ ! -x "$BREW_LOCATION" ]]; then + echo "[oh-my-zsh] $BREW_LOCATION is not executable" + return + fi + elif [[ -x /opt/homebrew/bin/brew ]]; then BREW_LOCATION="/opt/homebrew/bin/brew" elif [[ -x /usr/local/bin/brew ]]; then BREW_LOCATION="/usr/local/bin/brew" @@ -10,30 +15,41 @@ if (( ! $+commands[brew] )); then else return fi + + # Only add Homebrew installation to PATH, MANPATH, and INFOPATH if brew is + # not already on the path, to prevent duplicate entries. This aligns with + # the behavior of the brew installer.sh post-install steps. + eval "$("$BREW_LOCATION" shellenv)" + unset BREW_LOCATION fi if [[ -z "$HOMEBREW_PREFIX" ]]; then - if [[ -z $BREW_LOCATION ]]; then - eval "$(brew shellenv)" - else - eval "$("$BREW_LOCATION" shellenv)" - fi + # Maintain compatability with potential custom user profiles, where we had + # previously relied on always sourcing shellenv. OMZ plugins should not rely + # on this to be defined due to out of order processing. + export HOMEBREW_PREFIX="$(brew --prefix)" fi -unset BREW_LOCATION +if [[ -d "$HOMEBREW_PREFIX/share/zsh/site-functions" ]]; then + fpath+=("$HOMEBREW_PREFIX/share/zsh/site-functions") +fi alias bcubc='brew upgrade --cask && brew cleanup' alias bcubo='brew update && brew outdated --cask' +alias bcubc='brew upgrade --cask && brew cleanup' alias brewp='brew pin' alias brewsp='brew list --pinned' alias bubc='brew upgrade && brew cleanup' +alias bugbc='brew upgrade --greedy && brew cleanup' alias bubo='brew update && brew outdated' alias bubu='bubo && bubc' -alias buf='brew upgrade --formula' +alias bubug='bubo && bugbc' +alias bfu='brew upgrade --formula' +alias buz='brew uninstall --zap' function brews() { local formulae="$(brew leaves | xargs brew deps --installed --for-each)" - local casks="$(brew list --cask)" + local casks="$(brew list --cask 2>/dev/null)" local blue="$(tput setaf 4)" local bold="$(tput bold)" diff --git a/plugins/bridgetown/README.md b/plugins/bridgetown/README.md new file mode 100644 index 000000000..0a41814ee --- /dev/null +++ b/plugins/bridgetown/README.md @@ -0,0 +1,26 @@ +# Bridgetown plugin + +This plugin adds some aliases and autocompletion for common [Bridgetown](https://bridgetownrb.com/) commands. + +To use it, add `bridgetown` to the plugins array in your zshrc file: + +```zsh +plugins=(... bridgetown) +``` + +## Aliases + +| Alias | Command | +|-------|----------------------------| +| br | `bridgetown` | +| bra | `bin/bridgetown apply` | +| brb | `bin/bridgetown build` | +| brc | `bin/bridgetown console` | +| brclean | `bin/bridgetown clean` | +| brd | `bin/bridgetown deploy` | +| brdoc | `bin/bridgetown doctor` | +| brh | `bin/bridgetown help` | +| brn | `bridgetown new` | +| brp | `bridgetown plugins` | +| brpl | `bridgetown plugins list` | +| brs | `bin/bridgetown start` | diff --git a/plugins/bridgetown/bridgetown.plugin.zsh b/plugins/bridgetown/bridgetown.plugin.zsh new file mode 100644 index 000000000..502e9dfe0 --- /dev/null +++ b/plugins/bridgetown/bridgetown.plugin.zsh @@ -0,0 +1,12 @@ +alias br='bridgetown' +alias bra='bin/bridgetown apply' +alias brb='bin/bridgetown build' +alias brc='bin/bridgetown console' +alias brclean='bin/bridgetown clean' +alias brd='bin/bridgetown deploy' +alias brdoc='bin/bridgetown doctor' +alias brh='bin/bridgetown help' +alias brn='bridgetown new' +alias brp='bridgetown plugins' +alias brpl='bridgetown plugins list' +alias brs='bin/bridgetown start' diff --git a/plugins/bun/README.md b/plugins/bun/README.md new file mode 100644 index 000000000..5a312370f --- /dev/null +++ b/plugins/bun/README.md @@ -0,0 +1,20 @@ +# Bun Plugin + +This plugin sets up completion for [Bun](https://bun.sh). + +To use it, add `bun` to the plugins array in your zshrc file: + +```zsh +plugins=(... bun) +``` + +This plugin does not add any aliases. + +## Cache + +This plugin caches the completion script and is automatically updated when the +plugin is loaded, which is usually when you start up a new terminal emulator. + +The cache is stored at: + +- `$ZSH_CACHE_DIR/completions/_bun_` completions script diff --git a/plugins/bun/bun.plugin.zsh b/plugins/bun/bun.plugin.zsh new file mode 100644 index 000000000..9924faa84 --- /dev/null +++ b/plugins/bun/bun.plugin.zsh @@ -0,0 +1,14 @@ +# If Bun is not found, don't do the rest of the script +if (( ! $+commands[bun] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `bun`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_bun" ]]; then + typeset -g -A _comps + autoload -Uz _bun + _comps[bun]=_bun +fi + +bun completions >| "$ZSH_CACHE_DIR/completions/_bun" &| diff --git a/plugins/cakephp3/cakephp3.plugin.zsh b/plugins/cakephp3/cakephp3.plugin.zsh index dbfbeba3b..a1a289fd0 100644 --- a/plugins/cakephp3/cakephp3.plugin.zsh +++ b/plugins/cakephp3/cakephp3.plugin.zsh @@ -1,10 +1,10 @@ # CakePHP 3 basic command completion _cakephp3_get_command_list () { - bin/cake Completion commands + bin/cake completion commands } _cakephp3_get_sub_command_list () { - bin/cake Completion subcommands ${words[2]} + bin/cake completion subcommands ${words[2]} } _cakephp3_get_3rd_argument () { @@ -34,5 +34,5 @@ compdef _cakephp3 cake #Alias alias c3='bin/cake' -alias c3cache='bin/cake orm_cache clear' +alias c3cache='bin/cake schema_cache clear' alias c3migrate='bin/cake migrations migrate' diff --git a/plugins/coffee/_coffee b/plugins/coffee/_coffee index e2814f7ba..a771f5204 100644 --- a/plugins/coffee/_coffee +++ b/plugins/coffee/_coffee @@ -1,6 +1,6 @@ #compdef coffee # ------------------------------------------------------------------------------ -# Copyright (c) 2011 Github zsh-users - https://github.com/zsh-users +# Copyright (c) 2011 GitHub zsh-users - https://github.com/zsh-users # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/plugins/colored-man-pages/colored-man-pages.plugin.zsh b/plugins/colored-man-pages/colored-man-pages.plugin.zsh index 981992d88..57facbb5c 100644 --- a/plugins/colored-man-pages/colored-man-pages.plugin.zsh +++ b/plugins/colored-man-pages/colored-man-pages.plugin.zsh @@ -36,6 +36,7 @@ function colored() { # Prefer `less` whenever available, since we specifically configured # environment for it. environment+=( PAGER="${commands[less]:-$PAGER}" ) + environment+=( GROFF_NO_SGR=1 ) # See ./nroff script. if [[ "$OSTYPE" = solaris* ]]; then diff --git a/plugins/colorize/colorize.plugin.zsh b/plugins/colorize/colorize.plugin.zsh index a9da6cf83..12841e0ee 100644 --- a/plugins/colorize/colorize.plugin.zsh +++ b/plugins/colorize/colorize.plugin.zsh @@ -23,7 +23,7 @@ colorize_check_requirements() { if [[ ${available_tools[(Ie)$ZSH_COLORIZE_TOOL]} -eq 0 ]]; then echo "ZSH_COLORIZE_TOOL '$ZSH_COLORIZE_TOOL' not recognized. Available options are 'pygmentize' and 'chroma'." >&2 return 1 - elif (( $+commands["$ZSH_COLORIZE_TOOL"] )); then + elif ! (( $+commands[$ZSH_COLORIZE_TOOL] )); then echo "Package '$ZSH_COLORIZE_TOOL' is not installed!" >&2 return 1 fi diff --git a/plugins/command-not-found/command-not-found.plugin.zsh b/plugins/command-not-found/command-not-found.plugin.zsh index cb8a8989c..c741e18a2 100644 --- a/plugins/command-not-found/command-not-found.plugin.zsh +++ b/plugins/command-not-found/command-not-found.plugin.zsh @@ -3,9 +3,10 @@ for file ( # Arch Linux. Must have pkgfile installed: https://wiki.archlinux.org/index.php/Pkgfile#Command_not_found /usr/share/doc/pkgfile/command-not-found.zsh - # macOS (M1 and classic Homebrew): https://github.com/Homebrew/homebrew-command-not-found + # Homebrew: https://github.com/Homebrew/homebrew-command-not-found /opt/homebrew/Library/Taps/homebrew/homebrew-command-not-found/handler.sh /usr/local/Homebrew/Library/Taps/homebrew/homebrew-command-not-found/handler.sh + /home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/homebrew/homebrew-command-not-found/handler.sh ); do if [[ -r "$file" ]]; then source "$file" diff --git a/plugins/dbt/README.md b/plugins/dbt/README.md new file mode 100644 index 000000000..e05d79cc3 --- /dev/null +++ b/plugins/dbt/README.md @@ -0,0 +1,29 @@ +# dbt plugin + +## Introduction + +The `dbt plugin` adds several aliases for useful [dbt](https://docs.getdbt.com/) commands and +[aliases](#aliases). + +To use it, add `dbt` to the plugins array of your zshrc file: + +``` +plugins=(... dbt) +``` + +## Aliases + +| Alias | Command | Description | +| ------ | ------------------------------------------------ | ---------------------------------------------------- | +| dbtlm | `dbt ls -s state:modified` | List modified models only | +| dbtrm | `dbt run -s state:modified` | Run modified models only | +| dbttm | `dbt test -m state:modified` | Test modified models only | +| dbtrtm | `dbtrm && dbttm` | Run and test modified models only | +| dbtrs | `dbt clean; dbt deps; dbt seed` | Re-seed data | +| dbtfrt | `dbtrs; dbt run --full-refresh; dbt test` | Perform a full fresh run with tests | +| dbtcds | `dbt docs generate; dbt docs serve` | Generate docs without compiling | +| dbtds | `dbt docs generate --no-compile; dbt docs serve` | Generate and serve docs skipping doc. re-compilation | + +## Maintainer + +### [msempere](https://github.com/msempere) diff --git a/plugins/dbt/dbt.plugin.zsh b/plugins/dbt/dbt.plugin.zsh new file mode 100644 index 000000000..6fcc2eecf --- /dev/null +++ b/plugins/dbt/dbt.plugin.zsh @@ -0,0 +1,23 @@ +# list modified models only +alias dbtlm="dbt ls -s state:modified" + +# run modified models only +alias dbtrm="dbt run -s state:modified" + +# test modified models only +alias dbttm="dbt test -m state:modified" + +# run and test modified models only +alias dbtrtm="dbtrm && dbttm" + +# re-seed data +alias dbtrs="dbt clean; dbt deps; dbt seed" + +# perform a full fresh run with tests +alias dbtfrt="dbtrs; dbt run --full-refresh; dbt test" + +# generate and serve docs +alias dbtcds="dbt docs generate; dbt docs serve" + +# generate and serve docs skipping doc. re-compilation +alias dbtds="dbt docs generate --no-compile; dbt docs serve" diff --git a/plugins/debian/README.md b/plugins/debian/README.md index 2ce206cfb..6835ad65c 100644 --- a/plugins/debian/README.md +++ b/plugins/debian/README.md @@ -13,7 +13,12 @@ plugins=(... debian) - `$apt_pref`: use aptitude or apt if installed, fallback is apt-get. - `$apt_upgr`: use upgrade or safe-upgrade (for aptitude). -Set `$apt_pref` and `$apt_upgr` to whatever command you want (before sourcing Oh My Zsh) to override this behavior. +Set **both** `$apt_pref` and `$apt_upgr` to whatever command you want (before sourcing Oh My Zsh) to override this behavior, e.g.: + +```sh +apt_pref='apt' +apt_upgr='full-upgrade' +``` ## Common Aliases @@ -30,26 +35,25 @@ Set `$apt_pref` and `$apt_upgr` to whatever command you want (before sourcing Oh ## Superuser Operations Aliases -| Alias | Command | Description | -| -------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -| `aac` | `sudo $apt_pref autoclean` | Clears out the local repository of retrieved package files | -| `aar` | `sudo $apt_pref autoremove` | Removes packages installed automatically that are no longer needed | -| `abd` | `sudo $apt_pref build-dep` | Installs all dependencies for building packages | -| `ac` | `sudo $apt_pref clean` | Clears out the local repository of retrieved package files except lock files | -| `ad` | `sudo $apt_pref update` | Updates the package lists for upgrades for packages | -| `adg` | `sudo $apt_pref update && sudo $apt_pref $apt_upgr` | Update and upgrade packages | -| `ads` | `sudo apt-get dselect-upgrade` | Installs packages from list and removes all not in the list | -| `adu` | `sudo $apt_pref update && sudo $apt_pref dist-upgrade` | Smart upgrade that handles dependencies | -| `afu` | `sudo apt-file update` | Update the files in packages | -| `ai` | `sudo $apt_pref install` | Command-line tool to install package | -| `ail` | `sed -e 's/ */ /g' -e 's/ *//' \| cut -s -d ' ' -f 1 \| xargs sudo $apt_pref install` | Install all packages given on the command line while using only the first word of each line | -| `alu` | `sudo apt update && apt list -u && sudo apt upgrade` | Update, list and upgrade packages | -| `ap` | `sudo $apt_pref purge` | Removes packages along with configuration files | -| `ar` | `sudo $apt_pref remove` | Removes packages, keeps the configuration files | -| `au` | `sudo $apt_pref $apt_upgr` | Install package upgrades | -| `di` | `sudo dpkg -i` | Install all .deb files in the current directory | -| `dia` | `sudo dpkg -i ./*.deb` | Install all .deb files in the current directory | -| `kclean` | `sudo aptitude remove -P ?and(~i~nlinux-(ima\|hea) ?not(~n$(uname -r)))` | Remove ALL kernel images and headers EXCEPT the one in use | +| Alias | Command | Description | +| -------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | +| `aac` | `sudo $apt_pref autoclean` | Clears out the local repository of retrieved package files | +| `aar` | `sudo $apt_pref autoremove` | Removes packages installed automatically that are no longer needed | +| `abd` | `sudo $apt_pref build-dep` | Installs all dependencies for building packages | +| `ac` | `sudo $apt_pref clean` | Clears out the local repository of retrieved package files except lock files | +| `ad` | `sudo $apt_pref update` | Updates the package lists for upgrades for packages | +| `adg` | `sudo $apt_pref update && sudo $apt_pref $apt_upgr` | Update and upgrade packages | +| `ads` | `sudo apt-get dselect-upgrade` | Installs packages from list and removes all not in the list | +| `adu` | `sudo $apt_pref update && sudo $apt_pref dist-upgrade` | Smart upgrade that handles dependencies | +| `afu` | `sudo apt-file update` | Update the files in packages | +| `ai` | `sudo $apt_pref install` | Command-line tool to install package | +| `ail` | `sed -e 's/ */ /g' -e 's/ *//' \| cut -s -d ' ' -f 1 \| xargs sudo $apt_pref install` | Install all packages given on the command line while using only the first word of each line | +| `alu` | `sudo apt update && apt list -u && sudo apt upgrade` | Update, list and upgrade packages | +| `ap` | `sudo $apt_pref purge` | Removes packages along with configuration files | +| `au` | `sudo $apt_pref $apt_upgr` | Install package upgrades | +| `di` | `sudo dpkg -i` | Install all .deb files in the current directory | +| `dia` | `sudo dpkg -i ./*.deb` | Install all .deb files in the current directory | +| `kclean` | `sudo aptitude remove -P ?and(~i~nlinux-(ima\|hea) ?not(~n$(uname -r)))` | Remove ALL kernel images and headers EXCEPT the one in use | ## Aliases - Commands using `su` diff --git a/plugins/debian/debian.plugin.zsh b/plugins/debian/debian.plugin.zsh index f649a5b16..5ef4cfb67 100644 --- a/plugins/debian/debian.plugin.zsh +++ b/plugins/debian/debian.plugin.zsh @@ -51,11 +51,10 @@ if [[ $use_sudo -eq 1 ]]; then alias au="sudo $apt_pref $apt_upgr" alias ai="sudo $apt_pref install" # Install all packages given on the command line while using only the first word of each line: - # acs ... | ail + # acse ... | ail alias ail="sed -e 's/ */ /g' -e 's/ *//' | cut -s -d ' ' -f 1 | xargs sudo $apt_pref install" alias ap="sudo $apt_pref purge" - alias ar="sudo $apt_pref remove" alias aar="sudo $apt_pref autoremove" # apt-get only @@ -98,11 +97,6 @@ else print "$cmd" eval "$cmd" } - function ar() { - cmd="su -lc '$apt_pref remove $@' root" - print "$cmd" - eval "$cmd" - } function aar() { cmd="su -lc '$apt_pref autoremove $@' root" print "$cmd" @@ -147,7 +141,6 @@ apt_pref_compdef au "$apt_upgr" apt_pref_compdef ai "install" apt_pref_compdef ail "install" apt_pref_compdef ap "purge" -apt_pref_compdef ar "remove" apt_pref_compdef aar "autoremove" apt_pref_compdef ads "dselect-upgrade" diff --git a/plugins/deno/README.md b/plugins/deno/README.md index 691318397..38f9f2033 100644 --- a/plugins/deno/README.md +++ b/plugins/deno/README.md @@ -4,16 +4,17 @@ This plugin sets up completion and aliases for [Deno](https://deno.land). ## Aliases -| Alias | Full command | -| ----- | ---------------- | -| db | deno bundle | -| dc | deno compile | -| dca | deno cache | -| dfmt | deno fmt | -| dh | deno help | -| dli | deno lint | -| drn | deno run | -| drA | deno run -A | -| drw | deno run --watch | -| dts | deno test | -| dup | deno upgrade | +| Alias | Full command | +| ----- | ------------------- | +| db | deno bundle | +| dc | deno compile | +| dca | deno cache | +| dfmt | deno fmt | +| dh | deno help | +| dli | deno lint | +| drn | deno run | +| drA | deno run -A | +| drw | deno run --watch | +| dru | deno run --unstable | +| dts | deno test | +| dup | deno upgrade | diff --git a/plugins/deno/deno.plugin.zsh b/plugins/deno/deno.plugin.zsh index 7708f84df..bf97d6f03 100644 --- a/plugins/deno/deno.plugin.zsh +++ b/plugins/deno/deno.plugin.zsh @@ -8,6 +8,7 @@ alias dli='deno lint' alias drn='deno run' alias drA='deno run -A' alias drw='deno run --watch' +alias dru='deno run --unstable' alias dts='deno test' alias dup='deno upgrade' diff --git a/plugins/direnv/direnv.plugin.zsh b/plugins/direnv/direnv.plugin.zsh index 5e32c4c23..0a33194dd 100644 --- a/plugins/direnv/direnv.plugin.zsh +++ b/plugins/direnv/direnv.plugin.zsh @@ -7,10 +7,10 @@ _direnv_hook() { trap - SIGINT; } typeset -ag precmd_functions; -if [[ -z ${precmd_functions[(r)_direnv_hook]} ]]; then +if [[ -z "${precmd_functions[(r)_direnv_hook]+1}" ]]; then precmd_functions=( _direnv_hook ${precmd_functions[@]} ) fi typeset -ag chpwd_functions; -if [[ -z ${chpwd_functions[(r)_direnv_hook]} ]]; then +if [[ -z "${chpwd_functions[(r)_direnv_hook]+1}" ]]; then chpwd_functions=( _direnv_hook ${chpwd_functions[@]} ) fi diff --git a/plugins/dirhistory/dirhistory.plugin.zsh b/plugins/dirhistory/dirhistory.plugin.zsh index 7021fc03a..8d67c6188 100644 --- a/plugins/dirhistory/dirhistory.plugin.zsh +++ b/plugins/dirhistory/dirhistory.plugin.zsh @@ -19,15 +19,17 @@ export DIRHISTORY_SIZE=30 # Returns the element if the array was not empty, # otherwise returns empty string. function pop_past() { - typeset -g $1="${dirhistory_past[$#dirhistory_past]}" + setopt localoptions no_ksh_arrays if [[ $#dirhistory_past -gt 0 ]]; then + typeset -g $1="${dirhistory_past[$#dirhistory_past]}" dirhistory_past[$#dirhistory_past]=() fi } function pop_future() { - typeset -g $1="${dirhistory_future[$#dirhistory_future]}" + setopt localoptions no_ksh_arrays if [[ $#dirhistory_future -gt 0 ]]; then + typeset -g $1="${dirhistory_future[$#dirhistory_future]}" dirhistory_future[$#dirhistory_future]=() fi } @@ -35,6 +37,7 @@ function pop_future() { # Push a new element onto the end of dirhistory_past. If the size of the array # is >= DIRHISTORY_SIZE, the array is shifted function push_past() { + setopt localoptions no_ksh_arrays if [[ $#dirhistory_past -ge $DIRHISTORY_SIZE ]]; then shift dirhistory_past fi @@ -44,6 +47,7 @@ function push_past() { } function push_future() { + setopt localoptions no_ksh_arrays if [[ $#dirhistory_future -ge $DIRHISTORY_SIZE ]]; then shift dirhistory_future fi diff --git a/plugins/dnf/README.md b/plugins/dnf/README.md index dc0d1e0a0..f45c8778c 100644 --- a/plugins/dnf/README.md +++ b/plugins/dnf/README.md @@ -10,6 +10,9 @@ To use it, add `dnf` to the plugins array in your zshrc file: plugins=(... dnf) ``` +Classic `dnf` is getting superseded by `dnf5`; this plugin detects the presence +of `dnf5` and uses it as drop-in alternative to the slower `dnf`. + ## Aliases | Alias | Command | Description | diff --git a/plugins/dnf/dnf.plugin.zsh b/plugins/dnf/dnf.plugin.zsh index 653ce7dda..642422fe1 100644 --- a/plugins/dnf/dnf.plugin.zsh +++ b/plugins/dnf/dnf.plugin.zsh @@ -1,15 +1,19 @@ ## Aliases +local dnfprog="dnf" -alias dnfl="dnf list" # List packages -alias dnfli="dnf list installed" # List installed packages -alias dnfgl="dnf grouplist" # List package groups -alias dnfmc="dnf makecache" # Generate metadata cache -alias dnfp="dnf info" # Show package information -alias dnfs="dnf search" # Search package +# Prefer dnf5 if installed +command -v dnf5 > /dev/null && dnfprog=dnf5 -alias dnfu="sudo dnf upgrade" # Upgrade package -alias dnfi="sudo dnf install" # Install package -alias dnfgi="sudo dnf groupinstall" # Install package group -alias dnfr="sudo dnf remove" # Remove package -alias dnfgr="sudo dnf groupremove" # Remove package group -alias dnfc="sudo dnf clean all" # Clean cache +alias dnfl="${dnfprog} list" # List packages +alias dnfli="${dnfprog} list installed" # List installed packages +alias dnfgl="${dnfprog} grouplist" # List package groups +alias dnfmc="${dnfprog} makecache" # Generate metadata cache +alias dnfp="${dnfprog} info" # Show package information +alias dnfs="${dnfprog} search" # Search package + +alias dnfu="sudo ${dnfprog} upgrade" # Upgrade package +alias dnfi="sudo ${dnfprog} install" # Install package +alias dnfgi="sudo ${dnfprog} groupinstall" # Install package group +alias dnfr="sudo ${dnfprog} remove" # Remove package +alias dnfgr="sudo ${dnfprog} groupremove" # Remove package group +alias dnfc="sudo ${dnfprog} clean all" # Clean cache diff --git a/plugins/dnote/README.md b/plugins/dnote/README.md index e1b9b7044..7b41b9027 100644 --- a/plugins/dnote/README.md +++ b/plugins/dnote/README.md @@ -1,6 +1,6 @@ # Dnote Plugin -This plugin adds auto-completion for [Dnote](https://dnote.io) project. +This plugin adds auto-completion for [Dnote](https://www.getdnote.com/), a simple command line notebook. To use it, add `dnote` to the plugins array in your zshrc file: diff --git a/plugins/docker-compose/README.md b/plugins/docker-compose/README.md index 13f3c2cea..66d4e0521 100644 --- a/plugins/docker-compose/README.md +++ b/plugins/docker-compose/README.md @@ -11,22 +11,24 @@ plugins=(... docker-compose) ## Aliases -| Alias | Command | Description | -|-----------|--------------------------------|------------------------------------------------------------------| -| dco | `docker-compose` | Docker-compose main command | -| dcb | `docker-compose build` | Build containers | -| dce | `docker-compose exec` | Execute command inside a container | -| dcps | `docker-compose ps` | List containers | -| dcrestart | `docker-compose restart` | Restart container | -| dcrm | `docker-compose rm` | Remove container | -| dcr | `docker-compose run` | Run a command in container | -| dcstop | `docker-compose stop` | Stop a container | -| dcup | `docker-compose up` | Build, (re)create, start, and attach to containers for a service | -| dcupb | `docker-compose up --build` | Same as `dcup`, but build images before starting containers | -| dcupd | `docker-compose up -d` | Same as `dcup`, but starts as daemon | -| dcdn | `docker-compose down` | Stop and remove containers | -| dcl | `docker-compose logs` | Show logs of container | -| dclf | `docker-compose logs -f` | Show logs and follow output | -| dcpull | `docker-compose pull` | Pull image of a service | -| dcstart | `docker-compose start` | Start a container | -| dck | `docker-compose kill` | Kills containers | +| Alias | Command | Description | +|-----------|----------------------------------|----------------------------------------------------------------------------------| +| dco | `docker-compose` | Docker-compose main command | +| dcb | `docker-compose build` | Build containers | +| dce | `docker-compose exec` | Execute command inside a container | +| dcps | `docker-compose ps` | List containers | +| dcrestart | `docker-compose restart` | Restart container | +| dcrm | `docker-compose rm` | Remove container | +| dcr | `docker-compose run` | Run a command in container | +| dcstop | `docker-compose stop` | Stop a container | +| dcup | `docker-compose up` | Build, (re)create, start, and attach to containers for a service | +| dcupb | `docker-compose up --build` | Same as `dcup`, but build images before starting containers | +| dcupd | `docker-compose up -d` | Same as `dcup`, but starts as daemon | +| dcupdb | `docker-compose up -d --build` | Same as `dcup`, but build images before starting containers and starts as daemon | +| dcdn | `docker-compose down` | Stop and remove containers | +| dcl | `docker-compose logs` | Show logs of container | +| dclf | `docker-compose logs -f` | Show logs and follow output | +| dclF | `docker-compose logs -f --tail0` | Just follow recent logs | +| dcpull | `docker-compose pull` | Pull image of a service | +| dcstart | `docker-compose start` | Start a container | +| dck | `docker-compose kill` | Kills containers | diff --git a/plugins/docker-compose/docker-compose.plugin.zsh b/plugins/docker-compose/docker-compose.plugin.zsh index b8a4b067d..d1823f535 100644 --- a/plugins/docker-compose/docker-compose.plugin.zsh +++ b/plugins/docker-compose/docker-compose.plugin.zsh @@ -12,9 +12,11 @@ alias dcstop="$dccmd stop" alias dcup="$dccmd up" alias dcupb="$dccmd up --build" alias dcupd="$dccmd up -d" +alias dcupdb="$dccmd up -d --build" alias dcdn="$dccmd down" alias dcl="$dccmd logs" alias dclf="$dccmd logs -f" +alias dclF="$dccmd logs -f --tail 0" alias dcpull="$dccmd pull" alias dcstart="$dccmd start" alias dck="$dccmd kill" diff --git a/plugins/docker-machine/_docker-machine b/plugins/docker-machine/_docker-machine index fbd36d7c6..17bcd3598 100644 --- a/plugins/docker-machine/_docker-machine +++ b/plugins/docker-machine/_docker-machine @@ -335,9 +335,9 @@ _docker-machine() { '--tls-ca-key[Private key to generate certificates]:file:_files' \ '--tls-client-cert[Client cert to use for TLS]:file:_files' \ '--tls-client-key[Private key used in client TLS auth]:file:_files' \ - '--github-api-token[Token to use for requests to the Github API]' \ + '--github-api-token[Token to use for requests to the GitHub API]' \ '--native-ssh[Use the native (Go-based) SSH implementation.]' \ - '--bugsnag-api-token[BugSnag API token for crash reporting]' \ + '--bugsnag-api-token[Bugsnag API token for crash reporting]' \ '(- :)'{-v,--version}'[Print the version]' \ "(-): :->command" \ "(-)*:: :->option-or-argument" && ret=0 diff --git a/plugins/docker/README.md b/plugins/docker/README.md index 606690f14..0ab2e41fb 100644 --- a/plugins/docker/README.md +++ b/plugins/docker/README.md @@ -13,18 +13,15 @@ https://github.com/docker/cli/blob/master/contrib/completion/zsh/_docker ## Settings -By default, the completion doesn't allow option-stacking, meaning if you try to -complete `docker run -it ` it won't work, because you're _stacking_ the -`-i` and `-t` options. +By default, the completion doesn't allow option-stacking, meaning if you try to complete +`docker run -it ` it won't work, because you're _stacking_ the `-i` and `-t` options. -[You can enable it](https://github.com/docker/cli/commit/b10fb43048) by **adding -the lines below to your zshrc file**, but be aware of the side effects: +[You can enable it](https://github.com/docker/cli/commit/b10fb43048) by **adding the lines below to your zshrc +file**, but be aware of the side effects: -> This enables Zsh to understand commands like `docker run -it -> ubuntu`. However, by enabling this, this also makes Zsh complete -> `docker run -u` with `docker run -uapprox` which is not valid. The -> users have to put the space or the equal sign themselves before trying -> to complete. +> This enables Zsh to understand commands like `docker run -it ubuntu`. However, by enabling this, this also +> makes Zsh complete `docker run -u` with `docker run -uapprox` which is not valid. The users have to put +> the space or the equal sign themselves before trying to complete. > > Therefore, this behavior is disabled by default. To enable it: > @@ -33,41 +30,49 @@ the lines below to your zshrc file**, but be aware of the side effects: > zstyle ':completion:*:*:docker-*:*' option-stacking yes > ``` +### Use old-style completion + +If the current completion does not work well for you, you can enable legacy completion instead with the +following setting. See https://github.com/ohmyzsh/ohmyzsh/issues/11789 for more information. + +```zsh +zstyle ':omz:plugins:docker' legacy-completion yes +``` + ## Aliases -| Alias | Command | Description | -| :------ | :-------------------------- | :--------------------------------------------------------------------------------------- | -| dbl | `docker build` | Build an image from a Dockerfile | -| dcin | `docker container inspect` | Display detailed information on one or more containers | -| dlo | `docker container logs` | Fetch the logs of a docker container | -| dcls | `docker container ls` | List all the running docker containers | -| dclsa | `docker container ls -a` | List all running and stopped containers | -| dpo | `docker container port` | List port mappings or a specific mapping for the container | -| dpu | `docker pull` | Pull an image or a repository from a registry | -| dr | `docker container run` | Create a new container and start it using the specified command | -| drit | `docker container run -it` | Create a new container and start it in an interactive shell | -| drm | `docker container rm` | Remove the specified container(s) | -| drm! | `docker container rm -f` | Force the removal of a running container (uses SIGKILL) | -| dst | `docker container start` | Start one or more stopped containers | -| dstp | `docker container stop` | Stop one or more running containers | -| dtop | `docker top` | Display the running processes of a container | -| dxc | `docker container exec` | Run a new command in a running container | -| dxcit | `docker container exec -it` | Run a new command in a running container in an interactive shell | -| | | **Docker Images** | -| dib | `docker image build` | Build an image from a Dockerfile (same as docker build) | -| dii | `docker image inspect` | Display detailed information on one or more images | -| dils | `docker image ls` | List docker images | -| dipu | `docker image push` | Push an image or repository to a remote registry | -| dirm | `docker image rm` | Remove one or more images | -| dit | `docker image tag` | Add a name and tag to a particular image | -| | | **Docker Network** | -| dnc | `docker network create` | Create a new network | -| dncn | `docker network connect` | Connect a container to a network | -| dndcn | `docker network disconnect` | Disconnect a container from a network | -| dni | `docker network inspect` | Return information about one or more networks | -| dnls | `docker network ls` | List all networks the engine daemon knows about, including those spanning multiple hosts | -| dnrm | `docker network rm` | Remove one or more networks | -| | | **Docker Volume** | -| dvi | `docker volume inspect` | Display detailed information about one or more volumes | -| dvls | `docker volume ls` | List all the volumes known to docker | -| dvprune | `docker volume prune` | Cleanup dangling volumes | +| Alias | Command | Description | +| :------ | :---------------------------- | :--------------------------------------------------------------------------------------- | +| dbl | `docker build` | Build an image from a Dockerfile | +| dcin | `docker container inspect` | Display detailed information on one or more containers | +| dcls | `docker container ls` | List all the running docker containers | +| dclsa | `docker container ls -a` | List all running and stopped containers | +| dib | `docker image build` | Build an image from a Dockerfile (same as docker build) | +| dii | `docker image inspect` | Display detailed information on one or more images | +| dils | `docker image ls` | List docker images | +| dipu | `docker image push` | Push an image or repository to a remote registry | +| dirm | `docker image rm` | Remove one or more images | +| dit | `docker image tag` | Add a name and tag to a particular image | +| dlo | `docker container logs` | Fetch the logs of a docker container | +| dnc | `docker network create` | Create a new network | +| dncn | `docker network connect` | Connect a container to a network | +| dndcn | `docker network disconnect` | Disconnect a container from a network | +| dni | `docker network inspect` | Return information about one or more networks | +| dnls | `docker network ls` | List all networks the engine daemon knows about, including those spanning multiple hosts | +| dnrm | `docker network rm` | Remove one or more networks | +| dpo | `docker container port` | List port mappings or a specific mapping for the container | +| dpu | `docker pull` | Pull an image or a repository from a registry | +| dr | `docker container run` | Create a new container and start it using the specified command | +| drit | `docker container run -it` | Create a new container and start it in an interactive shell | +| drm | `docker container rm` | Remove the specified container(s) | +| drm! | `docker container rm -f` | Force the removal of a running container (uses SIGKILL) | +| dst | `docker container start` | Start one or more stopped containers | +| drs | `docker container restart` | Restart one or more containers | +| dsta | `docker stop $(docker ps -q)` | Stop all running containers | +| dstp | `docker container stop` | Stop one or more running containers | +| dtop | `docker top` | Display the running processes of a container | +| dvi | `docker volume inspect` | Display detailed information about one or more volumes | +| dvls | `docker volume ls` | List all the volumes known to docker | +| dvprune | `docker volume prune` | Cleanup dangling volumes | +| dxc | `docker container exec` | Run a new command in a running container | +| dxcit | `docker container exec -it` | Run a new command in a running container in an interactive shell | diff --git a/plugins/docker/_docker b/plugins/docker/completions/_docker similarity index 97% rename from plugins/docker/_docker rename to plugins/docker/completions/_docker index 8ee35abcf..466b09d94 100644 --- a/plugins/docker/_docker +++ b/plugins/docker/completions/_docker @@ -567,7 +567,7 @@ __docker_container_commands() { "cp:Copy files/folders between a container and the local filesystem" "create:Create a new container" "diff:Inspect changes on a container's filesystem" - "exec:Run a command in a running container" + "exec:Execute a command in a running container" "export:Export a container's filesystem as a tar archive" "inspect:Display detailed information on one or more containers" "kill:Kill one or more running containers" @@ -579,7 +579,7 @@ __docker_container_commands() { "rename:Rename a container" "restart:Restart one or more containers" "rm:Remove one or more containers" - "run:Run a command in a new container" + "run:Create and run a new container from an image" "start:Start one or more stopped containers" "stats:Display a live stream of container(s) resource usage statistics" "stop:Stop one or more running containers" @@ -602,6 +602,7 @@ __docker_container_subcommand() { opts_create_run=( "($help -a --attach)"{-a=,--attach=}"[Attach to stdin, stdout or stderr]:device:(STDIN STDOUT STDERR)" "($help)*--add-host=[Add a custom host-to-IP mapping]:host\:ip mapping: " + "($help)*--annotation=[Add an annotation to the container (passed through to the OCI runtime)]:annotations: " "($help)*--blkio-weight-device=[Block IO (relative device weight)]:device:Block IO weight: " "($help)*--cap-add=[Add Linux capabilities]:capability: " "($help)*--cap-drop=[Drop Linux capabilities]:capability: " @@ -650,6 +651,7 @@ __docker_container_subcommand() { "($help)*"{-p=,--publish=}"[Expose a container's port to the host]:port:_ports" "($help)--pid=[PID namespace to use]:PID namespace:__docker_complete_pid" "($help)--privileged[Give extended privileges to this container]" + "($help -q --quiet)"{-q,--quiet}"[Suppress the pull output]" "($help)--read-only[Mount the container's root filesystem as read only]" "($help)*--security-opt=[Security options]:security option: " "($help)*--shm-size=[Size of '/dev/shm' (format is '')]:shm size: " @@ -661,7 +663,7 @@ __docker_container_subcommand() { "($help)*--ulimit=[ulimit options]:ulimit: " "($help)--userns=[Container user namespace]:user namespace:(host)" "($help)--tmpfs[mount tmpfs]" - "($help)*-v[Bind mount a volume]:volume: " + "($help)*-v[Bind mount a volume]:volume:_directories -W / -P '/' -S '\:' -r '/ '" "($help)--volume-driver=[Optional volume driver for the container]:volume driver:(local)" "($help)*--volumes-from=[Mount volumes from the specified container]:volume: " "($help -w --workdir)"{-w=,--workdir=}"[Working directory inside the container]:directory:_directories" @@ -802,7 +804,7 @@ __docker_container_subcommand() { "($help -a --all)"{-a,--all}"[Show all containers]" \ "($help)--before=[Show only container created before...]:containers:__docker_complete_containers" \ "($help)*"{-f=,--filter=}"[Filter values]:filter:__docker_complete_ps_filters" \ - "($help)--format=[Pretty-print containers using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -l --latest)"{-l,--latest}"[Show only the latest created container]" \ "($help -n --last)"{-n=,--last=}"[Show n last created containers (includes all states)]:n:(1 5 10 25 50)" \ "($help)--no-trunc[Do not truncate output]" \ @@ -907,7 +909,7 @@ __docker_container_subcommand() { _arguments $(__docker_arguments) \ $opts_help \ "($help -a --all)"{-a,--all}"[Show all containers (default shows just running)]" \ - "($help)--format=[Pretty-print images using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help)--no-stream[Disable streaming stats and only pull the first result]" \ "($help)--no-trunc[Do not truncate output]" \ "($help -)*:containers:__docker_complete_running_containers" && ret=0 @@ -973,8 +975,8 @@ __docker_image_commands() { "load:Load an image from a tar archive or STDIN" "ls:List images" "prune:Remove unused images" - "pull:Pull an image or a repository from a registry" - "push:Push an image or a repository to a registry" + "pull:Download an image from a registry" + "push:Upload an image to a registry" "rm:Remove one or more images" "save:Save one or more images to a tar archive (streamed to STDOUT by default)" "tag:Tag an image into a repository" @@ -1060,7 +1062,7 @@ __docker_image_subcommand() { "($help -a --all)"{-a,--all}"[Show all images]" \ "($help)--digests[Show digests]" \ "($help)*"{-f=,--filter=}"[Filter values]:filter:__docker_complete_images_filters" \ - "($help)--format=[Pretty-print images using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help)--no-trunc[Do not truncate output]" \ "($help -q --quiet)"{-q,--quiet}"[Only show image IDs]" \ "($help -): :__docker_complete_repositories" && ret=0 @@ -1082,7 +1084,7 @@ __docker_image_subcommand() { (push) _arguments $(__docker_arguments) \ $opts_help \ - "($help -a --all-tags)"{-a,--all-tags}"[Push all tagged images in the repository]" \ + "($help -a --all-tags)"{-a,--all-tags}"[Push all tags of an image to the repository]" \ "($help)--disable-content-trust[Skip image signing]" \ "($help -): :__docker_complete_images" && ret=0 ;; @@ -1292,7 +1294,7 @@ __docker_network_subcommand() { $opts_help \ "($help)--no-trunc[Do not truncate the output]" \ "($help)*"{-f=,--filter=}"[Provide filter values]:filter:__docker_network_complete_ls_filters" \ - "($help)--format=[Pretty-print networks using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -q --quiet)"{-q,--quiet}"[Only display network IDs]" && ret=0 ;; (prune) @@ -2050,7 +2052,7 @@ __docker_service_subcommand() { _arguments $(__docker_arguments) \ $opts_help \ "($help)*"{-f=,--filter=}"[Filter output based on conditions provided]:filter:__docker_service_complete_ls_filters" \ - "($help)--format=[Pretty-print services using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -q --quiet)"{-q,--quiet}"[Only display IDs]" && ret=0 ;; (rm|remove) @@ -2253,7 +2255,7 @@ __docker_stack_subcommand() { _arguments $(__docker_arguments) \ $opts_help \ "($help)*"{-f=,--filter=}"[Filter output based on conditions provided]:filter:__docker_stack_complete_services_filters" \ - "($help)--format=[Pretty-print services using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -q --quiet)"{-q,--quiet}"[Only display IDs]" \ "($help -):stack:__docker_complete_stacks" && ret=0 ;; @@ -2520,12 +2522,14 @@ __docker_volume_subcommand() { _arguments $(__docker_arguments) \ $opts_help \ "($help)*"{-f=,--filter=}"[Provide filter values]:filter:__docker_volume_complete_ls_filters" \ - "($help)--format=[Pretty-print volumes using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -q --quiet)"{-q,--quiet}"[Only display volume names]" && ret=0 ;; (prune) _arguments $(__docker_arguments) \ $opts_help \ + "($help -a --all)"{-a,--all}"[Remove all unused local volumes, not just anonymous ones]" \ + "($help)*--filter=[Filter values]:filter:__docker_complete_prune_filters" \ "($help -f --force)"{-f,--force}"[Do not prompt for confirmation]" && ret=0 ;; (rm) @@ -2582,10 +2586,8 @@ __docker_context_subcommand() { (create) _arguments $(__docker_arguments) \ $opts_help \ - "($help)--default-stack-orchestrator=[Default orchestrator for stack operations to use with this context]:default-stack-orchestrator:(swarm kubernetes all)" \ "($help)--description=[Description of the context]:description:" \ "($help)--docker=[Set the docker endpoint]:docker:" \ - "($help)--kubernetes=[Set the kubernetes endpoint]:kubernetes:" \ "($help)--from=[Create context from a named context]:from:__docker_complete_contexts" \ "($help -):name: " && ret=0 ;; @@ -2607,10 +2609,8 @@ __docker_context_subcommand() { (update) _arguments $(__docker_arguments) \ $opts_help \ - "($help)--default-stack-orchestrator=[Default orchestrator for stack operations to use with this context]:default-stack-orchestrator:(swarm kubernetes all)" \ "($help)--description=[Description of the context]:description:" \ "($help)--docker=[Set the docker endpoint]:docker:" \ - "($help)--kubernetes=[Set the kubernetes endpoint]:kubernetes:" \ "($help -):name:" && ret=0 ;; esac @@ -2734,9 +2734,6 @@ __docker_subcommand() { "($help -b --bridge)"{-b=,--bridge=}"[Attach containers to a network bridge]:bridge:_net_interfaces" \ "($help)--bip=[Network bridge IP]:IP address: " \ "($help)--cgroup-parent=[Parent cgroup for all containers]:cgroup: " \ - "($help)--cluster-advertise=[Address or interface name to advertise]:Instance to advertise (host\:port): " \ - "($help)--cluster-store=[URL of the distributed storage backend]:Cluster Store:->cluster-store" \ - "($help)*--cluster-store-opt=[Cluster store options]:Cluster options:->cluster-store-options" \ "($help)--config-file=[Path to daemon configuration file]:Config File:_files" \ "($help)--containerd=[Path to containerd socket]:socket:_files -g \"*.sock\"" \ "($help)--containerd-namespace=[Containerd namespace to use]:containerd namespace:" \ @@ -2771,16 +2768,16 @@ __docker_subcommand() { "($help)--live-restore[Enable live restore of docker when containers are still running]" \ "($help)--log-driver=[Default driver for container logs]:logging driver:__docker_complete_log_drivers" \ "($help)*--log-opt=[Default log driver options for containers]:log driver options:__docker_complete_log_options" \ - "($help)--max-concurrent-downloads[Set the max concurrent downloads for each pull]" \ - "($help)--max-concurrent-uploads[Set the max concurrent uploads for each push]" \ + "($help)--max-concurrent-downloads[Set the max concurrent downloads]" \ + "($help)--max-concurrent-uploads[Set the max concurrent uploads]" \ "($help)--max-download-attempts[Set the max download attempts for each pull]" \ "($help)--mtu=[Network MTU]:mtu:(0 576 1420 1500 9000)" \ "($help)--oom-score-adjust=[Set the oom_score_adj for the daemon]:oom-score:(-500)" \ "($help -p --pidfile)"{-p=,--pidfile=}"[Path to use for daemon PID file]:PID file:_files" \ "($help)--raw-logs[Full timestamps without ANSI coloring]" \ - "($help)*--registry-mirror=[Preferred Docker registry mirror]:registry mirror: " \ + "($help)*--registry-mirror=[Preferred registry mirror]:registry mirror: " \ "($help)--seccomp-profile=[Path to seccomp profile]:path:_files -g \"*.json\"" \ - "($help -s --storage-driver)"{-s=,--storage-driver=}"[Storage driver to use]:driver:(aufs btrfs devicemapper overlay overlay2 vfs zfs)" \ + "($help -s --storage-driver)"{-s=,--storage-driver=}"[Storage driver to use]:driver:(btrfs devicemapper overlay2 vfs zfs)" \ "($help)--selinux-enabled[Enable selinux support]" \ "($help)--shutdown-timeout=[Set the shutdown timeout value in seconds]:time: " \ "($help)*--storage-opt=[Storage driver options]:storage driver options: " \ @@ -2795,22 +2792,6 @@ __docker_subcommand() { "($help)--validate[Validate daemon configuration and exit]" && ret=0 case $state in - (cluster-store) - if compset -P '*://'; then - _message 'host:port' && ret=0 - else - store=('consul' 'etcd' 'zk') - _describe -t cluster-store "Cluster Store" store -qS "://" && ret=0 - fi - ;; - (cluster-store-options) - if compset -P '*='; then - _files && ret=0 - else - opts=('discovery.heartbeat' 'discovery.ttl' 'kv.cacertfile' 'kv.certfile' 'kv.keyfile' 'kv.path') - _describe -t cluster-store-opts "Cluster Store Options" opts -qS "=" && ret=0 - fi - ;; (users-groups) if compset -P '*:'; then _groups && ret=0 @@ -3095,6 +3076,7 @@ _docker() { _arguments $(__docker_arguments) -C \ "(: -)"{-h,--help}"[Print usage]" \ "($help)--config[Location of client config files]:path:_directories" \ + "($help -c --context)"{-c=,--context=}"[Execute the command in a docker context]:context:__docker_complete_contexts" \ "($help -D --debug)"{-D,--debug}"[Enable debug mode]" \ "($help -H --host)"{-H=,--host=}"[tcp://host:port to bind/connect to]:host: " \ "($help -l --log-level)"{-l=,--log-level=}"[Logging level]:level:(debug info warn error fatal)" \ @@ -3110,7 +3092,8 @@ _docker() { local host=${opt_args[-H]}${opt_args[--host]} local config=${opt_args[--config]} - local docker_options="${host:+--host $host} ${config:+--config $config}" + local context=${opt_args[-c]}${opt_args[--context]} + local docker_options="${host:+--host $host} ${config:+--config $config} ${context:+--context $context} " case $state in (command) diff --git a/plugins/docker/docker.plugin.zsh b/plugins/docker/docker.plugin.zsh index 9c8ad8a28..7e657f2df 100644 --- a/plugins/docker/docker.plugin.zsh +++ b/plugins/docker/docker.plugin.zsh @@ -1,39 +1,62 @@ alias dbl='docker build' -alias dpu='docker pull' -alias dtop='docker top' - -# docker containers alias dcin='docker container inspect' -alias dlo='docker container logs' alias dcls='docker container ls' alias dclsa='docker container ls -a' -alias dpo='docker container port' -alias dr='docker container run' -alias drit='docker container run -it' -alias drm='docker container rm' -alias 'drm!'='docker container rm -f' -alias dst='docker container start' -alias dstp='docker container stop' -alias dxc='docker container exec' -alias dxcit='docker container exec -it' - -# docker images alias dib='docker image build' alias dii='docker image inspect' alias dils='docker image ls' alias dipu='docker image push' alias dirm='docker image rm' alias dit='docker image tag' - -# docker network +alias dlo='docker container logs' alias dnc='docker network create' alias dncn='docker network connect' alias dndcn='docker network disconnect' alias dni='docker network inspect' alias dnls='docker network ls' alias dnrm='docker network rm' - -# docker volume +alias dpo='docker container port' +alias dpu='docker pull' +alias dr='docker container run' +alias drit='docker container run -it' +alias drm='docker container rm' +alias 'drm!'='docker container rm -f' +alias dst='docker container start' +alias drs='docker container restart' +alias dsta='docker stop $(docker ps -q)' +alias dstp='docker container stop' +alias dtop='docker top' alias dvi='docker volume inspect' alias dvls='docker volume ls' alias dvprune='docker volume prune' +alias dxc='docker container exec' +alias dxcit='docker container exec -it' + +if (( ! $+commands[docker] )); then + return +fi + +# Standarized $0 handling +# https://zdharma-continuum.github.io/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html +0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" +0="${${(M)0:#/*}:-$PWD/$0}" + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `docker`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_docker" ]]; then + typeset -g -A _comps + autoload -Uz _docker + _comps[docker]=_docker +fi + +{ + # `docker completion` is only available from 23.0.0 on + # docker version returns `Docker version 24.0.2, build cb74dfcd85` + # with `s:,:` remove the comma after the version, and select third word of it + if zstyle -t ':omz:plugins:docker' legacy-completion || \ + ! is-at-least 23.0.0 ${${(s:,:z)"$(command docker --version)"}[3]}; then + command cp "${0:h}/completions/_docker" "$ZSH_CACHE_DIR/completions/_docker" + else + command docker completion zsh >| "$ZSH_CACHE_DIR/completions/_docker" + fi +} &| diff --git a/plugins/doctl/doctl.plugin.zsh b/plugins/doctl/doctl.plugin.zsh index d23ed085c..7b3a384a9 100644 --- a/plugins/doctl/doctl.plugin.zsh +++ b/plugins/doctl/doctl.plugin.zsh @@ -4,6 +4,14 @@ # # Author: https://github.com/HalisCz -if [ $commands[doctl] ]; then - source <(doctl completion zsh) +if (( ! $+commands[doctl] )); then + return fi + +if [[ ! -f "$ZSH_CACHE_DIR/completions/_doctl" ]]; then + typeset -g -A _comps + autoload -Uz _doctl + _comps[doctl]=_doctl +fi + +doctl completion zsh >| "$ZSH_CACHE_DIR/completions/_doctl" &| diff --git a/plugins/dotnet/README.md b/plugins/dotnet/README.md index 87dfd8f8d..a15e80577 100644 --- a/plugins/dotnet/README.md +++ b/plugins/dotnet/README.md @@ -17,6 +17,7 @@ plugins=(... dotnet) | dt | dotnet test | Run unit tests using the test runner specified in a .NET project. | | dw | dotnet watch | Watch for source file changes and restart the dotnet command. | | dwr | dotnet watch run | Watch for source file changes and restart the `run` command. | +| dwt | dotnet watch test| Watch for source file changes and restart the `test` command. | | ds | dotnet sln | Modify Visual Studio solution files. | | da | dotnet add | Add a package or reference to a .NET project. | | dp | dotnet pack | Create a NuGet package. | diff --git a/plugins/dotnet/dotnet.plugin.zsh b/plugins/dotnet/dotnet.plugin.zsh index 8ea31cdbd..40ee7efae 100644 --- a/plugins/dotnet/dotnet.plugin.zsh +++ b/plugins/dotnet/dotnet.plugin.zsh @@ -1,22 +1,14 @@ # This scripts is copied from (MIT License): -# https://github.com/dotnet/toolset/blob/master/scripts/register-completions.zsh +# https://raw.githubusercontent.com/dotnet/sdk/main/scripts/register-completions.zsh -_dotnet_zsh_complete() -{ - local completions=("$(dotnet complete "$words")") - - # If the completion list is empty, just continue with filename selection - if [ -z "$completions" ] - then - _arguments '*::arguments: _normal' - return - fi - - # This is not a variable assignment, don't remove spaces! - _values = "${(ps:\n:)completions}" +#compdef dotnet +_dotnet_completion() { + local -a completions=("${(@f)$(dotnet complete "${words}")}") + compadd -a completions + _files } -compdef _dotnet_zsh_complete dotnet +compdef _dotnet_completion dotnet # Aliases bellow are here for backwards compatibility # added by Shaun Tabone (https://github.com/xontab) @@ -26,6 +18,7 @@ alias dr='dotnet run' alias dt='dotnet test' alias dw='dotnet watch' alias dwr='dotnet watch run' +alias dwt='dotnet watch test' alias ds='dotnet sln' alias da='dotnet add' alias dp='dotnet pack' diff --git a/plugins/emacs/README.md b/plugins/emacs/README.md index c8e33b5ab..8ed4a1473 100644 --- a/plugins/emacs/README.md +++ b/plugins/emacs/README.md @@ -25,6 +25,6 @@ The plugin uses a custom launcher (which we'll call here `$EMACS_LAUNCHER`) that | e | `emacs` | Same as emacs alias | | te | `$EMACS_LAUNCHER -nw` | Open terminal emacsclient | | eeval | `$EMACS_LAUNCHER --eval` | Same as `M-x eval` but from outside Emacs | -| eframe | `emacsclient --alternate-editor "" --create-frame` | Create new X frame | +| eframe | `emacsclient --alternate-editor="" --create-frame` | Create new X frame | | efile | - | Print the path to the file open in the current buffer | | ecd | - | Print the directory of the file open in the the current buffer | diff --git a/plugins/emacs/emacs.plugin.zsh b/plugins/emacs/emacs.plugin.zsh index fede5b0c4..4747f035b 100644 --- a/plugins/emacs/emacs.plugin.zsh +++ b/plugins/emacs/emacs.plugin.zsh @@ -32,7 +32,7 @@ alias te="$EMACS_PLUGIN_LAUNCHER -nw" # same than M-x eval but from outside Emacs. alias eeval="$EMACS_PLUGIN_LAUNCHER --eval" # create a new X frame -alias eframe='emacsclient --alternate-editor "" --create-frame' +alias eframe='emacsclient --alternate-editor="" --create-frame' # Emacs ANSI Term tracking if [[ -n "$INSIDE_EMACS" ]]; then diff --git a/plugins/emacs/emacsclient.sh b/plugins/emacs/emacsclient.sh index 96893c932..172c0ae96 100755 --- a/plugins/emacs/emacsclient.sh +++ b/plugins/emacs/emacsclient.sh @@ -15,11 +15,11 @@ emacsfun() { # Only create another X frame if there isn't one present if [ -z "$frames" -o "$frames" = nil ]; then - emacsclient --alternate-editor "" --create-frame "$@" + emacsclient --alternate-editor="" --create-frame "$@" return $? fi - emacsclient --alternate-editor "" "$@" + emacsclient --alternate-editor="" "$@" } # Adapted from https://github.com/davidshepherd7/emacs-read-stdin/blob/master/emacs-read-stdin.sh diff --git a/plugins/emoji/update_emoji.py b/plugins/emoji/update_emoji.py index eb945b9ef..18b3c060d 100644 --- a/plugins/emoji/update_emoji.py +++ b/plugins/emoji/update_emoji.py @@ -56,7 +56,7 @@ typeset -gAH emoji_groups # def country_iso(_all_names, _omz_name): # """ Using the external library country_converter, -# this funciton can detect the ISO2 and ISO3 codes +# this function can detect the ISO2 and ISO3 codes # of the country. It takes as argument the array # with all the names of the emoji, and returns that array.""" # omz_no_underscore = re.sub(r'_', r' ', _omz_name) @@ -96,7 +96,7 @@ def name_to_omz(_name, _group, _subgroup, _status): # Special treatment by status # Enables us to have every emoji combination, # even the one that are not officially sanctionned - # and are implemeted by, say, only one vendor + # and are implemented by, say, only one vendor if _status == "unqualified": shortname += "_unqualified" elif _status == "minimally-qualified": diff --git a/plugins/encode64/README.md b/plugins/encode64/README.md index 86320cffb..7cdf8c3f3 100644 --- a/plugins/encode64/README.md +++ b/plugins/encode64/README.md @@ -10,10 +10,11 @@ plugins=(... encode64) ## Functions and Aliases -| Function | Alias | Description | -| ---------- | ----- | ------------------------------ | -| `encode64` | `e64` | Encodes given data to base64 | -| `decode64` | `d64` | Decodes given data from base64 | +| Function | Alias | Description | +| -------------- | ------ | -------------------------------------- | +| `encode64` | `e64` | Encodes given data to base64 | +| `encodefile64` | `ef64` | Encodes given file's content to base64 | +| `decode64` | `d64` | Decodes given data from base64 | ## Usage and examples @@ -37,6 +38,20 @@ plugins=(... encode64) b2gtbXktenNo== ``` +### Encoding a file + +Encode a file's contents to base64 and save output to text file. +**NOTE:** Takes provided file and saves encoded content as new file with `.txt` extension + +- From parameter + + ```console + $ encodefile64 ohmyzsh.icn + ohmyzsh.icn's content encoded in base64 and saved as ohmyzsh.icn.txt + $ ef64 "oh-my-zsh" + ohmyzsh.icn's content encoded in base64 and saved as ohmyzsh.icn.txt + ``` + ### Decoding - From parameter diff --git a/plugins/encode64/encode64.plugin.zsh b/plugins/encode64/encode64.plugin.zsh index 979e06742..6927f5216 100644 --- a/plugins/encode64/encode64.plugin.zsh +++ b/plugins/encode64/encode64.plugin.zsh @@ -6,6 +6,15 @@ encode64() { fi } +encodefile64() { + if [[ $# -eq 0 ]]; then + echo "You must provide a filename" + else + base64 -i $1 -o $1.txt + echo "${1}'s content encoded in base64 and saved as ${1}.txt" + fi +} + decode64() { if [[ $# -eq 0 ]]; then cat | base64 --decode @@ -14,4 +23,5 @@ decode64() { fi } alias e64=encode64 +alias ef64=encodefile64 alias d64=decode64 diff --git a/plugins/extract/README.md b/plugins/extract/README.md index 44f0b05a1..c8d98b229 100644 --- a/plugins/extract/README.md +++ b/plugins/extract/README.md @@ -1,10 +1,10 @@ # extract plugin -This plugin defines a function called `extract` that extracts the archive file -you pass it, and it supports a wide variety of archive filetypes. +This plugin defines a function called `extract` that extracts the archive file you pass it, and it supports a +wide variety of archive filetypes. -This way you don't have to know what specific command extracts a file, you just -do `extract ` and the function takes care of the rest. +This way you don't have to know what specific command extracts a file, you just do `extract ` and +the function takes care of the rest. To use it, add `extract` to the plugins array in your zshrc file: @@ -15,7 +15,7 @@ plugins=(... extract) ## Supported file extensions | Extension | Description | -|:------------------|:-------------------------------------| +| :---------------- | :----------------------------------- | | `7z` | 7zip file | | `Z` | Z archive (LZW) | | `apk` | Android app file | @@ -25,6 +25,7 @@ plugins=(... extract) | `cpio` | Cpio archive | | `deb` | Debian package | | `ear` | Enterprise Application aRchive | +| `exe` | Windows executable file | | `gz` | Gzip file | | `ipa` | iOS app package | | `ipsw` | iOS firmware file | @@ -32,6 +33,7 @@ plugins=(... extract) | `lrz` | LRZ archive | | `lz4` | LZ4 archive | | `lzma` | LZMA archive | +| `obscpio` | cpio archive used on OBS | | `rar` | WinRAR archive | | `rpm` | RPM package | | `sublime-package` | Sublime Text package | @@ -51,10 +53,13 @@ plugins=(... extract) | `txz` | Tarball with lzma2 compression | | `tzst` | Tarball with zstd compression | | `war` | Web Application archive (Java-based) | +| `whl` | Python wheel file | | `xpi` | Mozilla XPI module file | | `xz` | LZMA2 archive | | `zip` | Zip archive | +| `zlib` | zlib archive | | `zst` | Zstandard file (zstd) | +| `zpaq` | Zpaq file | -See [list of archive formats](https://en.wikipedia.org/wiki/List_of_archive_formats) for -more information regarding archive formats. +See [list of archive formats](https://en.wikipedia.org/wiki/List_of_archive_formats) for more information +regarding archive formats. diff --git a/plugins/extract/_extract b/plugins/extract/_extract index 27b099c9e..56b17058f 100644 --- a/plugins/extract/_extract +++ b/plugins/extract/_extract @@ -3,5 +3,5 @@ _arguments \ '(-r --remove)'{-r,--remove}'[Remove archive.]' \ - "*::archive file:_files -g '(#i)*.(7z|Z|apk|aar|bz2|cab|cpio|deb|ear|gz|ipa|ipsw|jar|lrz|lz4|lzma|rar|rpm|sublime-package|tar|tar.bz2|tar.gz|tar.lrz|tar.lz|tar.lz4|tar.xz|tar.zma|tar.zst|tbz|tbz2|tgz|tlz|txz|tzst|war|whl|xpi|xz|zip|zst)(-.)'" \ + "*::archive file:_files -g '(#i)*.(7z|Z|apk|aar|bz2|cab|cpio|deb|ear|gz|ipa|ipsw|jar|lrz|lz4|lzma|obscpio|rar|rpm|sublime-package|tar|tar.bz2|tar.gz|tar.lrz|tar.lz|tar.lz4|tar.xz|tar.zma|tar.zst|tbz|tbz2|tgz|tlz|txz|tzst|war|whl|xpi|xz|zip|zst|zpaq)(-.)'" \ && return 0 diff --git a/plugins/extract/extract.plugin.zsh b/plugins/extract/extract.plugin.zsh index 1112dd52f..88d8b0740 100644 --- a/plugins/extract/extract.plugin.zsh +++ b/plugins/extract/extract.plugin.zsh @@ -27,59 +27,111 @@ EOF fi local success=0 - local extract_dir="${1:t:r}" local file="$1" full_path="${1:A}" + local extract_dir="${1:t:r}" + + # Remove the .tar extension if the file name is .tar.* + if [[ $extract_dir =~ '\.tar$' ]]; then + extract_dir="${extract_dir:r}" + fi + + # If there's a file or directory with the same name as the archive + # add a random string to the end of the extract directory + if [[ -e "$extract_dir" ]]; then + local rnd="${(L)"${$(( [##36]$RANDOM*$RANDOM ))}":1:5}" + extract_dir="${extract_dir}-${rnd}" + fi + + # Create an extraction directory based on the file name + command mkdir -p "$extract_dir" + builtin cd -q "$extract_dir" + echo "extract: extracting to $extract_dir" >&2 + case "${file:l}" in - (*.tar.gz|*.tgz) (( $+commands[pigz] )) && { pigz -dc "$file" | tar xv } || tar zxvf "$file" ;; - (*.tar.bz2|*.tbz|*.tbz2) tar xvjf "$file" ;; + (*.tar.gz|*.tgz) + (( $+commands[pigz] )) && { tar -I pigz -xvf "$full_path" } || tar zxvf "$full_path" ;; + (*.tar.bz2|*.tbz|*.tbz2) + (( $+commands[pbzip2] )) && { tar -I pbzip2 -xvf "$full_path" } || tar xvjf "$full_path" ;; (*.tar.xz|*.txz) + (( $+commands[pixz] )) && { tar -I pixz -xvf "$full_path" } || { tar --xz --help &> /dev/null \ - && tar --xz -xvf "$file" \ - || xzcat "$file" | tar xvf - ;; + && tar --xz -xvf "$full_path" \ + || xzcat "$full_path" | tar xvf - } ;; (*.tar.zma|*.tlz) tar --lzma --help &> /dev/null \ - && tar --lzma -xvf "$file" \ - || lzcat "$file" | tar xvf - ;; + && tar --lzma -xvf "$full_path" \ + || lzcat "$full_path" | tar xvf - ;; (*.tar.zst|*.tzst) tar --zstd --help &> /dev/null \ - && tar --zstd -xvf "$file" \ - || zstdcat "$file" | tar xvf - ;; - (*.tar) tar xvf "$file" ;; - (*.tar.lz) (( $+commands[lzip] )) && tar xvf "$file" ;; - (*.tar.lz4) lz4 -c -d "$file" | tar xvf - ;; - (*.tar.lrz) (( $+commands[lrzuntar] )) && lrzuntar "$file" ;; - (*.gz) (( $+commands[pigz] )) && pigz -dk "$file" || gunzip -k "$file" ;; - (*.bz2) bunzip2 "$file" ;; - (*.xz) unxz "$file" ;; - (*.lrz) (( $+commands[lrunzip] )) && lrunzip "$file" ;; - (*.lz4) lz4 -d "$file" ;; - (*.lzma) unlzma "$file" ;; - (*.z) uncompress "$file" ;; - (*.zip|*.war|*.jar|*.ear|*.sublime-package|*.ipa|*.ipsw|*.xpi|*.apk|*.aar|*.whl) unzip "$file" -d "$extract_dir" ;; - (*.rar) unrar x -ad "$file" ;; + && tar --zstd -xvf "$full_path" \ + || zstdcat "$full_path" | tar xvf - ;; + (*.tar) tar xvf "$full_path" ;; + (*.tar.lz) (( $+commands[lzip] )) && tar xvf "$full_path" ;; + (*.tar.lz4) lz4 -c -d "$full_path" | tar xvf - ;; + (*.tar.lrz) (( $+commands[lrzuntar] )) && lrzuntar "$full_path" ;; + (*.gz) (( $+commands[pigz] )) && pigz -cdk "$full_path" > "${file:t:r}" || gunzip -ck "$full_path" > "${file:t:r}" ;; + (*.bz2) bunzip2 "$full_path" ;; + (*.xz) unxz "$full_path" ;; + (*.lrz) (( $+commands[lrunzip] )) && lrunzip "$full_path" ;; + (*.lz4) lz4 -d "$full_path" ;; + (*.lzma) unlzma "$full_path" ;; + (*.z) uncompress "$full_path" ;; + (*.zip|*.war|*.jar|*.ear|*.sublime-package|*.ipa|*.ipsw|*.xpi|*.apk|*.aar|*.whl) unzip "$full_path" ;; + (*.rar) unrar x -ad "$full_path" ;; (*.rpm) - command mkdir -p "$extract_dir" && builtin cd -q "$extract_dir" \ - && rpm2cpio "$full_path" | cpio --quiet -id ;; - (*.7z) 7za x "$file" ;; + rpm2cpio "$full_path" | cpio --quiet -id ;; + (*.7z) 7za x "$full_path" ;; (*.deb) - command mkdir -p "$extract_dir/control" "$extract_dir/data" - builtin cd -q "$extract_dir"; ar vx "$full_path" > /dev/null + command mkdir -p "control" "data" + ar vx "$full_path" > /dev/null builtin cd -q control; extract ../control.tar.* builtin cd -q ../data; extract ../data.tar.* builtin cd -q ..; command rm *.tar.* debian-binary ;; - (*.zst) unzstd "$file" ;; - (*.cab) cabextract -d "$extract_dir" "$file" ;; - (*.cpio) cpio -idmvF "$file" ;; + (*.zst) unzstd "$full_path" ;; + (*.cab|*.exe) cabextract "$full_path" ;; + (*.cpio|*.obscpio) cpio -idmvF "$full_path" ;; + (*.zpaq) zpaq x "$full_path" ;; + (*.zlib) zlib-flate -uncompress < "$full_path" > "${file:r}" ;; (*) echo "extract: '$file' cannot be extracted" >&2 success=1 ;; esac (( success = success > 0 ? success : $? )) - (( success == 0 && remove_archive == 0 )) && rm "$full_path" + (( success == 0 && remove_archive == 0 )) && command rm "$full_path" shift - # Go back to original working directory in case we ran cd previously + # Go back to original working directory builtin cd -q "$pwd" + + # If content of extract dir is a single directory, move its contents up + # Glob flags: + # - D: include files starting with . + # - N: no error if directory is empty + # - Y2: at most give 2 files + local -a content + content=("${extract_dir}"/*(DNY2)) + if [[ ${#content} -eq 1 && -e "${content[1]}" ]]; then + # The extracted file/folder (${content[1]}) may have the same name as $extract_dir + # If so, we need to rename it to avoid conflicts in a 3-step process + # + # 1. Move and rename the extracted file/folder to a temporary random name + # 2. Delete the empty folder + # 3. Rename the extracted file/folder to the original name + if [[ "${content[1]:t}" == "$extract_dir" ]]; then + # =(:) gives /tmp/zsh, with :t it gives zsh + local tmp_name==(:); tmp_name="${tmp_name:t}" + command mv "${content[1]}" "$tmp_name" \ + && command rmdir "$extract_dir" \ + && command mv "$tmp_name" "$extract_dir" + # Otherwise, if the extracted folder name already exists in the current + # directory (because of a previous file / folder), keep the extract_dir + elif [[ ! -e "${content[1]:t}" ]]; then + command mv "${content[1]}" . \ + && command rmdir "$extract_dir" + fi + elif [[ ${#content} -eq 0 ]]; then + command rmdir "$extract_dir" + fi done } diff --git a/plugins/fasd/README.md b/plugins/fasd/README.md index a5c74e5b8..7c44ac84d 100644 --- a/plugins/fasd/README.md +++ b/plugins/fasd/README.md @@ -10,7 +10,7 @@ plugins=(... fasd) ## Installation -Please find detailed installation guide [`here`](https://github.com/clvv/fasd#install) +Please find detailed installation guide [`here`](https://github.com/whjvenyl/fasd#install) ## Aliases diff --git a/plugins/firewalld/firewalld.plugin.zsh b/plugins/firewalld/firewalld.plugin.zsh index 5b1090636..b2c0f64be 100644 --- a/plugins/firewalld/firewalld.plugin.zsh +++ b/plugins/firewalld/firewalld.plugin.zsh @@ -9,7 +9,7 @@ function fwl () { zones=("${(@f)$(sudo firewall-cmd --get-active-zones | grep -v 'interfaces\|sources')}") for i in $zones; do - sudo firewall-cmd --zone $i --list-all + sudo firewall-cmd --zone ${i/ \(default\)} --list-all done echo 'Direct Rules:' diff --git a/plugins/fluxcd/README.md b/plugins/fluxcd/README.md new file mode 100644 index 000000000..9723fcc6b --- /dev/null +++ b/plugins/fluxcd/README.md @@ -0,0 +1,9 @@ +# FluxCD plugin + +This plugin adds completion for [FluxCD](https://fluxcd.io), an open and extensible continuous delivery solution for Kubernetes. Powered by GitOps Toolkit. + +To use it, add `fluxcd` to the plugins array in your zshrc file: + +```zsh +plugins=(... fluxcd) +``` diff --git a/plugins/fluxcd/fluxcd.plugin.zsh b/plugins/fluxcd/fluxcd.plugin.zsh new file mode 100644 index 000000000..d30866a06 --- /dev/null +++ b/plugins/fluxcd/fluxcd.plugin.zsh @@ -0,0 +1,14 @@ +# Autocompletion for the FluxCD CLI (flux). +if (( ! $+commands[flux] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `flux`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_flux" ]]; then + typeset -g -A _comps + autoload -Uz _flux + _comps[flux]=_flux +fi + +flux completion zsh >| "$ZSH_CACHE_DIR/completions/_flux" &| diff --git a/plugins/fossil/fossil.plugin.zsh b/plugins/fossil/fossil.plugin.zsh index a2123f415..fadf6095d 100644 --- a/plugins/fossil/fossil.plugin.zsh +++ b/plugins/fossil/fossil.plugin.zsh @@ -13,12 +13,11 @@ ZSH_THEME_FOSSIL_PROMPT_DIRTY=" %{$fg_bold[red]%}✖" ZSH_THEME_FOSSIL_PROMPT_CLEAN=" %{$fg_bold[green]%}✔" function fossil_prompt_info() { - local info=$(fossil branch 2>&1) + local branch=$(fossil branch current 2>&1) # if we're not in a fossil repo, don't show anything - ! command grep -q "use --repo" <<< "$info" || return + ! command grep -q "use --repo" <<< "$branch" || return - local branch=$(echo $info | grep "* " | sed 's/* //g') local changes=$(fossil changes) local dirty="$ZSH_THEME_FOSSIL_PROMPT_CLEAN" diff --git a/plugins/frontend-search/README.md b/plugins/frontend-search/README.md index 050058931..920795060 100644 --- a/plugins/frontend-search/README.md +++ b/plugins/frontend-search/README.md @@ -60,12 +60,22 @@ Available search contexts are: | typescript | `https://google.com/search?as_sitesearch=www.typescriptlang.org/docs&as_q=` | | unheap | `http://www.unheap.com/?s=` | | vuejs | `https://www.google.com/search?as_sitesearch=vuejs.org&as_q=` | +| nextjs | `https://www.google.com/search?as_sitesearch=nextjs.org&as_q=` | If you want to have another context, open an Issue and tell us! ## Fallback search behaviour -The plugin will use Google as a fallback if the docs site for a search context does not have a search function. You can set the fallback search engine to DuckDuckGo by setting `FRONTEND_SEARCH_FALLBACK='duckduckgo'` in your `~/.zshrc` file before Oh My Zsh is sourced. +The plugin will use Google as a fallback if the docs site for a search context does not have a search +function. You can set the fallback search engine to DuckDuckGo by setting +`FRONTEND_SEARCH_FALLBACK='duckduckgo'` in your `~/.zshrc` file before Oh My Zsh is sourced. + +## DuckDuckGo Lucky Search + +Enable DuckDuckGo's "ducky" (lucky) search feature to automatically access the top search result. This feature +is optimized for DuckDuckGo, as Google redirects to an intermediate page. The FRONTEND_SEARCH_FALLBACK_LUCKY +environment variable triggers the use of DuckDuckGo's lucky search, rendering the FRONTEND_SEARCH_FALLBACK +setting unnecessary in this context. ## Author diff --git a/plugins/frontend-search/_frontend b/plugins/frontend-search/_frontend index 15f8d239d..aca4920d7 100644 --- a/plugins/frontend-search/_frontend +++ b/plugins/frontend-search/_frontend @@ -37,7 +37,7 @@ function _frontend() { 'lodash: Search in Lo-Dash website' 'mdn: Search in MDN website' 'nodejs: Search in NodeJS website' - 'npmjs: Search in NPMJS website' + 'npmjs: Search in npmjs website' 'packagephobia: Search in Packagephobia website' 'qunit: Search in Qunit website' 'reactjs: Search in React website' diff --git a/plugins/frontend-search/frontend-search.plugin.zsh b/plugins/frontend-search/frontend-search.plugin.zsh index b9e2fe95d..c96596eb9 100644 --- a/plugins/frontend-search/frontend-search.plugin.zsh +++ b/plugins/frontend-search/frontend-search.plugin.zsh @@ -27,12 +27,19 @@ alias stackoverflow='frontend stackoverflow' alias typescript='frontend typescript' alias unheap='frontend unheap' alias vuejs='frontend vuejs' +alias nextjs='frontend nextjs' function _frontend_fallback() { - case "$FRONTEND_SEARCH_FALLBACK" in - duckduckgo) echo "https://duckduckgo.com/?sites=$1&q=" ;; - *) echo "https://google.com/search?as_sitesearch=$1&as_q=" ;; - esac + if [[ "$FRONTEND_SEARCH_FALLBACK_LUCKY" == "true" ]]; then + case true in + *) echo "https://duckduckgo.com/?q=!ducky+site%3A$1+" ;; + esac + else + case "$FRONTEND_SEARCH_FALLBACK" in + duckduckgo) echo "https://duckduckgo.com/?sites=$1&q=" ;; + *) echo "https://google.com/search?as_sitesearch=$1&as_q=" ;; + esac + fi } function frontend() { @@ -70,6 +77,7 @@ function frontend() { typescript $(_frontend_fallback 'www.typescriptlang.org/docs') unheap 'http://www.unheap.com/?s=' vuejs $(_frontend_fallback 'vuejs.org') + nextjs $(_frontend_fallback 'nextjs.org') ) # show help for command list @@ -81,7 +89,7 @@ function frontend() { print -P "" print -P " angular, angularjs, bem, bootsnipp, caniuse, codepen, compassdoc, cssflow, packagephobia" print -P " dartlang, emberjs, fontello, flowtype, github, html5please, jestjs, jquery, lodash," - print -P " mdn, npmjs, nodejs, qunit, reactjs, smacss, stackoverflow, unheap, vuejs, bundlephobia" + print -P " mdn, npmjs, nodejs, qunit, reactjs, smacss, stackoverflow, unheap, vuejs, bundlephobia, nextjs" print -P "" print -P "For example: frontend npmjs mocha (or just: npmjs mocha)." print -P "" @@ -96,7 +104,7 @@ function frontend() { echo "" echo " angular, angularjs, bem, bootsnipp, caniuse, codepen, compassdoc, cssflow, packagephobia" echo " dartlang, emberjs, fontello, github, html5please, jest, jquery, lodash," - echo " mdn, npmjs, nodejs, qunit, reactjs, smacss, stackoverflow, unheap, vuejs, bundlephobia" + echo " mdn, npmjs, nodejs, qunit, reactjs, smacss, stackoverflow, unheap, vuejs, bundlephobia, nextjs" echo "" return 1 fi diff --git a/plugins/fzf/fzf.plugin.zsh b/plugins/fzf/fzf.plugin.zsh index a946cf762..b253a23d2 100644 --- a/plugins/fzf/fzf.plugin.zsh +++ b/plugins/fzf/fzf.plugin.zsh @@ -9,6 +9,7 @@ function fzf_setup_using_base_dir() { "${HOME}/.nix-profile/share/fzf" "${XDG_DATA_HOME:-$HOME/.local/share}/fzf" "/usr/local/opt/fzf" + "/opt/homebrew/opt/fzf" "/usr/share/fzf" "/usr/local/share/examples/fzf" ) @@ -59,8 +60,8 @@ function fzf_setup_using_base_dir() { function fzf_setup_using_debian() { - if (( ! $+commands[dpkg] )) || ! dpkg -s fzf &>/dev/null; then - # Either not a debian based distro, or no fzf installed + if (( ! $+commands[apt] && ! $+commands[apt-get] )); then + # Not a debian based distro return 1 fi @@ -71,11 +72,19 @@ function fzf_setup_using_debian() { case $PREFIX in *com.termux*) + if [[ ! -f "${PREFIX}/bin/fzf" ]]; then + # fzf not installed + return 1 + fi # Support Termux package completions="${PREFIX}/share/fzf/completion.zsh" key_bindings="${PREFIX}/share/fzf/key-bindings.zsh" ;; *) + if [[ ! -d /usr/share/doc/fzf/examples ]]; then + # fzf not installed + return 1 + fi # Determine completion file path: first bullseye/sid, then buster/stretch completions="/usr/share/doc/fzf/examples/completion.zsh" [[ -f "$completions" ]] || completions="/usr/share/zsh/vendor-completions/_fzf" @@ -178,7 +187,7 @@ function fzf_setup_using_macports() { (( $+commands[fzf] )) || return 1 # The fzf-zsh-completion package installs the auto-completion in - local completions="/opt/local/share/zsh/site-functions/fzf" + local completions="/opt/local/share/fzf/shell/completion.zsh" # The fzf-zsh-completion package installs the key-bindings file in local key_bindings="/opt/local/share/fzf/shell/key-bindings.zsh" diff --git a/plugins/gas/README.md b/plugins/gas/README.md index 47b3fb9df..a0a7a568f 100644 --- a/plugins/gas/README.md +++ b/plugins/gas/README.md @@ -1,6 +1,6 @@ # Gas plugin -This plugin adds autocompletion for the [gas](http://walle.github.com/gas) command, +This plugin adds autocompletion for the [gas](http://ramblingsby.me/gas/) command, a utility to manage Git authors. To use it, add `gas` to the plugins array of your zshrc file: diff --git a/plugins/gcloud/gcloud.plugin.zsh b/plugins/gcloud/gcloud.plugin.zsh index 7368eb3a6..9a4213aaf 100644 --- a/plugins/gcloud/gcloud.plugin.zsh +++ b/plugins/gcloud/gcloud.plugin.zsh @@ -6,12 +6,17 @@ if [[ -z "${CLOUDSDK_HOME}" ]]; then search_locations=( "$HOME/google-cloud-sdk" + "/usr/local/share/google-cloud-sdk" "/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk" "/opt/homebrew/Caskroom/google-cloud-sdk/latest/google-cloud-sdk" "/usr/share/google-cloud-sdk" "/snap/google-cloud-sdk/current" - "/usr/lib64/google-cloud-sdk/" + "/snap/google-cloud-cli/current" + "/usr/lib/google-cloud-sdk" + "/usr/lib64/google-cloud-sdk" "/opt/google-cloud-sdk" + "/opt/google-cloud-cli" + "/opt/local/libexec/google-cloud-sdk" ) for gcloud_sdk_location in $search_locations; do @@ -20,15 +25,26 @@ if [[ -z "${CLOUDSDK_HOME}" ]]; then break fi done + unset search_locations gcloud_sdk_location fi if (( ${+CLOUDSDK_HOME} )); then - if (( ! $+commands[gcloud] )); then - # Only source this if GCloud isn't already on the path - if [[ -f "${CLOUDSDK_HOME}/path.zsh.inc" ]]; then - source "${CLOUDSDK_HOME}/path.zsh.inc" - fi + # Source path file + if [[ -f "${CLOUDSDK_HOME}/path.zsh.inc" ]]; then + source "${CLOUDSDK_HOME}/path.zsh.inc" fi - source "${CLOUDSDK_HOME}/completion.zsh.inc" + + # Look for completion file in different paths + for comp_file ( + "${CLOUDSDK_HOME}/completion.zsh.inc" # default location + "/usr/share/google-cloud-sdk/completion.zsh.inc" # apt-based location + ); do + if [[ -f "${comp_file}" ]]; then + source "${comp_file}" + break + fi + done + unset comp_file + export CLOUDSDK_HOME fi diff --git a/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh b/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh index 2e029639c..f8dfec759 100644 --- a/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh +++ b/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh @@ -28,7 +28,8 @@ function git-fetch-all { # Fetch all remotes (avoid ssh passphrase prompt) date -R &>! "$gitdir/FETCH_LOG" GIT_SSH_COMMAND="command ssh -o BatchMode=yes" \ - command git fetch --all 2>/dev/null &>> "$gitdir/FETCH_LOG" + GIT_TERMINAL_PROMPT=0 \ + command git fetch --all --recurse-submodules=yes 2>/dev/null &>> "$gitdir/FETCH_LOG" ) &| } diff --git a/plugins/git-commit/README.md b/plugins/git-commit/README.md new file mode 100644 index 000000000..91cc73b44 --- /dev/null +++ b/plugins/git-commit/README.md @@ -0,0 +1,42 @@ +# git-commit plugin + +The git-commit plugin adds several [git aliases](https://www.git-scm.com/docs/git-config#Documentation/git-config.txt-alias) for [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/#summary) messages. + +To use it, add `git-commit` to the plugins array in your zshrc file: + +```zsh +plugins=(... git-commit) +``` + +## Syntax + +```zsh +git [(-s, --scope) ""] "" +``` + +> ⚠️ Single/Double quotes around the scope and message are required + +Where `type` is one of the following: + +- `build` +- `chore` +- `ci` +- `docs` +- `feat` +- `fix` +- `perf` +- `refactor` +- `rev` +- `style` +- `test` + +> NOTE: the alias for `revert` type is `rev`, as otherwise it conflicts with the git command of the same name. +> It will still generate a commit message in the format `revert: ` + +## Examples + +| Git alias | Command | +| --------------------------------------------- | ---------------------------------------------------- | +| `git style "remove trailing whitespace"` | `git commit -m "style: remove trailing whitespace"` | +| `git fix -s "router" "correct redirect link"` | `git commit -m "fix(router): correct redirect link"` | +| `git rev -s "api" "rollback v2"` | `git commit -m "revert(api): rollback v2"` | diff --git a/plugins/git-commit/git-commit.plugin.zsh b/plugins/git-commit/git-commit.plugin.zsh new file mode 100644 index 000000000..72cecb1d6 --- /dev/null +++ b/plugins/git-commit/git-commit.plugin.zsh @@ -0,0 +1,31 @@ +local -a _git_commit_aliases +_git_commit_aliases=( + 'build' + 'chore' + 'ci' + 'docs' + 'feat' + 'fix' + 'perf' + 'refactor' + 'revert' + 'style' + 'test' +) + +local alias type +for type in "${_git_commit_aliases[@]}"; do + # an alias can't be named "revert" because the git command takes precedence + # https://stackoverflow.com/a/3538791 + case "$type" in + revert) alias=rev ;; + *) alias=$type ;; + esac + + local func='!a() { if [ "$1" = "-s" ] || [ "$1" = "--scope" ]; then local scope="$2"; shift 2; git commit -m "'$type'(${scope}): ${@}"; else git commit -m "'$type': ${@}"; fi }; a' + if ! git config --global --get-all alias.${alias} >/dev/null 2>&1; then + git config --global alias.${alias} "$func" + fi +done + +unset _git_commit_aliases alias type func diff --git a/plugins/git-extras/README.md b/plugins/git-extras/README.md index 2adc9d477..7eb53fcfd 100644 --- a/plugins/git-extras/README.md +++ b/plugins/git-extras/README.md @@ -1,6 +1,6 @@ # git-extras -This plugin provides completion definitions for some of the commands defined by [git-extras](https://github.com/tj/git-extras). +This plugin provides completion definitions for some of the commands defined by [git-extras](https://github.com/tj/git-extras), which must already be installed. To use it, add `git-extras` to the plugins array in your zshrc file: diff --git a/plugins/git-extras/git-extras.plugin.zsh b/plugins/git-extras/git-extras.plugin.zsh index b86d7c5b6..f5fd387d1 100644 --- a/plugins/git-extras/git-extras.plugin.zsh +++ b/plugins/git-extras/git-extras.plugin.zsh @@ -51,7 +51,7 @@ __gitex_remote_names() { local expl declare -a remote_names remote_names=(${(f)"$(_call_program remotes git remote 2>/dev/null)"}) - __git_command_successful || return + __gitex_command_successful || return _wanted remote-names expl remote-name compadd $* - $remote_names } @@ -59,7 +59,7 @@ __gitex_tag_names() { local expl declare -a tag_names tag_names=(${${(f)"$(_call_program tags git for-each-ref --format='"%(refname)"' refs/tags 2>/dev/null)"}#refs/tags/}) - __git_command_successful || return + __gitex_command_successful || return _wanted tag-names expl tag-name compadd $* - $tag_names } @@ -68,7 +68,7 @@ __gitex_branch_names() { local expl declare -a branch_names branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads 2>/dev/null)"}#refs/heads/}) - __git_command_successful || return + __gitex_command_successful || return _wanted branch-names expl branch-name compadd $* - $branch_names } @@ -76,31 +76,19 @@ __gitex_specific_branch_names() { local expl declare -a branch_names branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads/"$1" 2>/dev/null)"}#refs/heads/$1/}) - __git_command_successful || return + __gitex_command_successful || return _wanted branch-names expl branch-name compadd - $branch_names } -__gitex_chore_branch_names() { - __gitex_specific_branch_names 'chore' -} - __gitex_feature_branch_names() { __gitex_specific_branch_names 'feature' } -__gitex_refactor_branch_names() { - __gitex_specific_branch_names 'refactor' -} - -__gitex_bug_branch_names() { - __gitex_specific_branch_names 'bug' -} - __gitex_submodule_names() { local expl declare -a submodule_names submodule_names=(${(f)"$(_call_program branchrefs git submodule status | awk '{print $2}')"}) # ' - __git_command_successful || return + __gitex_command_successful || return _wanted submodule-names expl submodule-name compadd $* - $submodule_names } @@ -109,93 +97,34 @@ __gitex_author_names() { local expl declare -a author_names author_names=(${(f)"$(_call_program branchrefs git log --format='%aN' | sort -u)"}) - __git_command_successful || return + __gitex_command_successful || return _wanted author-names expl author-name compadd $* - $author_names } # subcommands +# new subcommand should be added in alphabetical order _git-authors() { _arguments -C \ '(--list -l)'{--list,-l}'[show authors]' \ '--no-email[without email]' \ } -_git-bug() { - local curcontext=$curcontext state line ret=1 - declare -A opt_args - - _arguments -C \ - ': :->command' \ - '*:: :->option-or-argument' && ret=0 - - case $state in - (command) - declare -a commands - commands=( - 'finish:merge bug into the current branch' - ) - _describe -t commands command commands && ret=0 - ;; - (option-or-argument) - curcontext=${curcontext%:*}-$line[1]: - case $line[1] in - (finish) - _arguments -C \ - ':branch-name:__gitex_bug_branch_names' - ;; - -r|--remote ) - _arguments -C \ - ':remote-name:__gitex_remote_names' - ;; - esac - return 0 - esac - - _arguments \ - '(--remote -r)'{--remote,-r}'[setup remote tracking branch]' -} - - _git-changelog() { _arguments \ '(-l --list)'{-l,--list}'[list commits]' \ } -_git-chore() { - local curcontext=$curcontext state line ret=1 - declare -A opt_args - - _arguments -C \ - ': :->command' \ - '*:: :->option-or-argument' && ret=0 - - case $state in - (command) - declare -a commands - commands=( - 'finish:merge and delete the chore branch' - ) - _describe -t commands command commands && ret=0 - ;; - (option-or-argument) - curcontext=${curcontext%:*}-$line[1]: - case $line[1] in - (finish) - _arguments -C \ - ':branch-name:__gitex_chore_branch_names' - ;; - -r|--remote ) - _arguments -C \ - ':remote-name:__gitex_remote_names' - ;; - esac - return 0 - esac - +_git-clear() { _arguments \ - '(--remote -r)'{--remote,-r}'[setup remote tracking branch]' + '(-f --force)'{-f,--force}'[force clear]' \ + '(-h --help)'{-h,--help}'[help message]' \ } +_git-coauthor() { + _arguments \ + ':co-author[co-author to add]' \ + ':co-author-email[email address of co-author to add]' +} _git-contrib() { _arguments \ @@ -235,6 +164,11 @@ _git-delete-branch() { ':branch-name:__gitex_branch_names' } +_git-delete-squashed-branches() { + _arguments \ + ':branch-name:__gitex_branch_names' +} + _git-delete-submodule() { _arguments \ @@ -298,6 +232,7 @@ _git-feature() { case $line[1] in (finish) _arguments -C \ + '--squash[Use squash merge]' \ ':branch-name:__gitex_feature_branch_names' ;; -r|--remote ) @@ -327,20 +262,17 @@ _git-guilt() { } _git-ignore() { - _arguments -C \ + _arguments -C \ '(--local -l)'{--local,-l}'[show local gitignore]' \ '(--global -g)'{--global,-g}'[show global gitignore]' \ '(--private -p)'{--private,-p}'[show repo gitignore]' } -_git-ignore() { - _arguments -C \ - '(--append -a)'{--append,-a}'[append .gitignore]' \ - '(--replace -r)'{--replace,-r}'[replace .gitignore]' \ - '(--list-in-table -l)'{--list-in-table,-l}'[print available types in table format]' \ - '(--list-alphabetically -L)'{--list-alphabetically,-L}'[print available types in alphabetical order]' \ - '(--search -s)'{--search,-s}'[search word in available types]' +_git-info() { + _arguments -C \ + '(--color -c)'{--color,-c}'[use color for information titles]' \ + '--no-config[do not show list all variables set in config file, along with their values]' } @@ -357,50 +289,27 @@ _git-missing() { ':second-branch-name:__gitex_branch_names' } - -_git-refactor() { - local curcontext=$curcontext state line ret=1 - declare -A opt_args - +_git-release() { _arguments -C \ - ': :->command' \ - '*:: :->option-or-argument' && ret=0 - - case $state in - (command) - declare -a commands - commands=( - 'finish:merge refactor into the current branch' - ) - _describe -t commands command commands && ret=0 - ;; - (option-or-argument) - curcontext=${curcontext%:*}-$line[1]: - case $line[1] in - (finish) - _arguments -C \ - ':branch-name:__gitex_refactor_branch_names' - ;; - -r|--remote ) - _arguments -C \ - ':remote-name:__gitex_remote_names' - ;; - esac - return 0 - esac - - _arguments \ - '(--remote -r)'{--remote,-r}'[setup remote tracking branch]' + '-c[Generates/populates the changelog with all commit message since the last tag.]' \ + '-r[The "remote" repository that is destination of a push operation.]' \ + '-m[use the custom commit information instead of the default message.]' \ + '-s[Create a signed and annotated tag.]' \ + '-u[Create a tag, annotated and signed with the given key.]' \ + '--semver[If the latest tag in your repo matches the semver format requirement, you could increase part of it as the new release tag.]' \ + '--prefix[Add a prefix string to semver to allow more complex tags.]' \ + '--no-empty-commit[Avoid creating empty commit if nothing could be committed.]' \ + '--[The arguments listed after "--" separator will be passed to pre/post-release hook.]' } - _git-squash() { + _arguments '--squash-msg[commit with the squashed commit messages]' _arguments \ ':branch-name:__gitex_branch_names' } _git-stamp() { - _arguments -C \ + _arguments -C \ '(--replace -r)'{--replace,-r}'[replace stamps with same id]' } @@ -413,17 +322,19 @@ _git-standup() { '-g[Display GPG signed info]' \ '-h[Display help message]' \ '-L[Enable the inclusion of symbolic links]' \ - '-m[The depth of recursive directory search]' + '-m[The depth of recursive directory search]' \ + '-B[Display the commits in branch groups]' } _git-summary() { _arguments '--line[summarize with lines rather than commits]' + _arguments '--dedup-by-email[remove duplicate users by the email address]' + _arguments '--no-merges[exclude merge commits]' __gitex_commits } - _git-undo(){ - _arguments -C \ + _arguments -C \ '(--soft -s)'{--soft,-s}'[only rolls back the commit but changes remain un-staged]' \ '(--hard -h)'{--hard,-h}'[wipes your commit(s)]' } @@ -432,21 +343,26 @@ zstyle -g existing_user_commands ':completion:*:*:git:*' user-commands zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \ alias:'define, search and show aliases' \ + abort:'abort current revert, merge, rebase, or cherry-pick process' \ archive-file:'export the current head of the git repository to an archive' \ authors:'generate authors report' \ - back:'undo and stage latest commits' \ + browse:'open repo website in browser' \ + browse-ci:'open repo CI page in browser' \ bug:'create bug branch' \ bulk:'run bulk commands' \ + brv:'list branches sorted by their last commit date'\ changelog:'generate a changelog report' \ chore:'create chore branch' \ clear-soft:'soft clean up a repository' \ clear:'rigorously clean up a repository' \ + coauthor:'add a co-author to the last commit' \ commits-since:'show commit logs since some date' \ contrib:'show user contributions' \ count:'show commit count' \ create-branch:'create branches' \ delete-branch:'delete branches' \ delete-merged-branches:'delete merged branches' \ + delete-squashed-branches:'delete squashed branches' \ delete-submodule:'delete submodules' \ delete-tag:'delete tags' \ delta:'lists changed files' \ @@ -465,11 +381,13 @@ zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \ local-commits:'list local commits' \ lock:'lock a file excluded from version control' \ locked:'ls files that have been locked' \ + magic:'commits everything with a generated message' \ merge-into:'merge one branch into another' \ merge-repo:'merge two repo histories' \ missing:'show commits missing from another branch' \ mr:'checks out a merge request locally' \ obliterate:'rewrite past commits to remove some files' \ + paste:'send patches to pastebin sites' \ pr:'checks out a pull request locally' \ psykorebase:'rebase a branch with a merge commit' \ pull-request:'create pull request to GitHub project' \ @@ -479,6 +397,7 @@ zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \ release:'commit, tag and push changes to the repository' \ rename-branch:'rename a branch' \ rename-tag:'rename a tag' \ + rename-remote:'rename a remote' \ repl:'git read-eval-print-loop' \ reset-file:'reset one file' \ root:'show path of root' \ @@ -495,4 +414,5 @@ zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \ sync:'sync local branch with remote branch' \ touch:'touch and add file to the index' \ undo:'remove latest commits' \ - unlock:'unlock a file excluded from version control' + unlock:'unlock a file excluded from version control' \ + utimes:'change files modification time to their last commit date' diff --git a/plugins/git-prompt/README.md b/plugins/git-prompt/README.md index 8775af893..05208d72f 100644 --- a/plugins/git-prompt/README.md +++ b/plugins/git-prompt/README.md @@ -45,6 +45,7 @@ The symbols are as follows: | ●n | there are `n` staged files | | ✖n | there are `n` unmerged files | | ✚n | there are `n` unstaged files | +| -n | there are `n` deleted files | | ⚑n | there are `n` stashed changes | | … | there are some untracked files | @@ -59,6 +60,7 @@ The symbols are as follows: ## Customisation - Set the variable `ZSH_THEME_GIT_PROMPT_CACHE` to any value in order to enable caching. +- Set the variable `ZSH_THEME_GIT_SHOW_UPSTREAM` to any value to display the upstream branch. - You may also change a number of variables (whose name start with `ZSH_THEME_GIT_PROMPT_`) to change the appearance of the prompt. Take a look at the bottom of the [plugin file](git-prompt.plugin.zsh)` to see what variables are available. diff --git a/plugins/git-prompt/git-prompt.plugin.zsh b/plugins/git-prompt/git-prompt.plugin.zsh index 0485e317c..487332028 100644 --- a/plugins/git-prompt/git-prompt.plugin.zsh +++ b/plugins/git-prompt/git-prompt.plugin.zsh @@ -47,12 +47,19 @@ function update_current_git_vars() { GIT_UNTRACKED=$__CURRENT_GIT_STATUS[7] GIT_STASHED=$__CURRENT_GIT_STATUS[8] GIT_CLEAN=$__CURRENT_GIT_STATUS[9] + GIT_DELETED=$__CURRENT_GIT_STATUS[10] + + if [ -z ${ZSH_THEME_GIT_SHOW_UPSTREAM+x} ]; then + GIT_UPSTREAM= + else + GIT_UPSTREAM=$(git rev-parse --abbrev-ref --symbolic-full-name "@{upstream}" 2>/dev/null) && GIT_UPSTREAM="${ZSH_THEME_GIT_PROMPT_UPSTREAM_SEPARATOR}${GIT_UPSTREAM}" + fi } git_super_status() { precmd_update_git_vars if [ -n "$__CURRENT_GIT_STATUS" ]; then - STATUS="$ZSH_THEME_GIT_PROMPT_PREFIX$ZSH_THEME_GIT_PROMPT_BRANCH$GIT_BRANCH%{${reset_color}%}" + STATUS="$ZSH_THEME_GIT_PROMPT_PREFIX$ZSH_THEME_GIT_PROMPT_BRANCH$GIT_BRANCH$GIT_UPSTREAM%{${reset_color}%}" if [ "$GIT_BEHIND" -ne "0" ]; then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_BEHIND$GIT_BEHIND%{${reset_color}%}" fi @@ -69,6 +76,9 @@ git_super_status() { if [ "$GIT_CHANGED" -ne "0" ]; then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_CHANGED$GIT_CHANGED%{${reset_color}%}" fi + if [ "$GIT_DELETED" -ne "0" ]; then + STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_DELETED$GIT_DELETED%{${reset_color}%}" + fi if [ "$GIT_UNTRACKED" -ne "0" ]; then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_UNTRACKED$GIT_UNTRACKED%{${reset_color}%}" fi @@ -91,11 +101,13 @@ ZSH_THEME_GIT_PROMPT_BRANCH="%{$fg_bold[magenta]%}" ZSH_THEME_GIT_PROMPT_STAGED="%{$fg[red]%}%{●%G%}" ZSH_THEME_GIT_PROMPT_CONFLICTS="%{$fg[red]%}%{✖%G%}" ZSH_THEME_GIT_PROMPT_CHANGED="%{$fg[blue]%}%{✚%G%}" +ZSH_THEME_GIT_PROMPT_DELETED="%{$fg[blue]%}%{-%G%}" ZSH_THEME_GIT_PROMPT_BEHIND="%{↓%G%}" ZSH_THEME_GIT_PROMPT_AHEAD="%{↑%G%}" ZSH_THEME_GIT_PROMPT_UNTRACKED="%{$fg[cyan]%}%{…%G%}" ZSH_THEME_GIT_PROMPT_STASHED="%{$fg_bold[blue]%}%{⚑%G%}" ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[green]%}%{✔%G%}" +ZSH_THEME_GIT_PROMPT_UPSTREAM_SEPARATOR="->" # Set the prompt. RPROMPT='$(git_super_status)' diff --git a/plugins/git-prompt/gitstatus.py b/plugins/git-prompt/gitstatus.py index b5c3c9a0c..94774d828 100644 --- a/plugins/git-prompt/gitstatus.py +++ b/plugins/git-prompt/gitstatus.py @@ -44,7 +44,7 @@ if po.returncode != 0: sys.exit(0) # Not a git repository # collect git status information -untracked, staged, changed, conflicts = [], [], [], [] +untracked, staged, changed, deleted, conflicts = [], [], [], [], [] ahead, behind = 0, 0 status = [(line[0], line[1], line[2:]) for line in stdout.decode('utf-8').splitlines()] for st in status: @@ -75,13 +75,15 @@ for st in status: else: if st[1] == 'M': changed.append(st) + if st[1] == 'D': + deleted.append(st) if st[0] == 'U': conflicts.append(st) elif st[0] != ' ': staged.append(st) stashed = get_stash() -if not changed and not staged and not conflicts and not untracked: +if not changed and not deleted and not staged and not conflicts and not untracked: clean = 1 else: clean = 0 @@ -95,6 +97,7 @@ out = ' '.join([ str(len(changed)), str(len(untracked)), str(stashed), - str(clean) + str(clean), + str(len(deleted)) ]) print(out, end='') diff --git a/plugins/git/README.md b/plugins/git/README.md index 050c13d81..b7b9a6635 100644 --- a/plugins/git/README.md +++ b/plugins/git/README.md @@ -10,239 +10,270 @@ plugins=(... git) ## Aliases -| Alias | Command | -|:---------------------|:---------------------------------------------------------------------------------------------------------------------------------| -| g | git | -| ga | git add | -| gaa | git add --all | -| gapa | git add --patch | -| gau | git add --update | -| gav | git add --verbose | -| gap | git apply | -| gapt | git apply --3way | -| gb | git branch | -| gba | git branch -a | -| gbd | git branch -d | -| gbda | git branch --no-color --merged \| grep -vE "^([+*]\|\s*($(git_main_branch)\|$(git_develop_branch))\s*$)" \| xargs git branch -d 2>/dev/null | -| gbD | git branch -D | -| gbl | git blame -b -w | -| gbnm | git branch --no-merged | -| gbr | git branch --remote | -| gbs | git bisect | -| gbsb | git bisect bad | -| gbsg | git bisect good | -| gbsr | git bisect reset | -| gbss | git bisect start | -| gc | git commit -v | -| gc! | git commit -v --amend | -| gcn! | git commit -v --no-edit --amend | -| gca | git commit -v -a | -| gca! | git commit -v -a --amend | -| gcan! | git commit -v -a --no-edit --amend | -| gcans! | git commit -v -a -s --no-edit --amend | -| gcam | git commit -a -m | -| gcas | git commit -a -s | -| gcasm | git commit -a -s -m | -| gcsm | git commit -s -m | -| gcb | git checkout -b | -| gcf | git config --list | -| gcl | git clone --recurse-submodules | -| gccd | git clone --recurse-submodules "$@" && cd "$(basename $_ .git)" | -| gclean | git clean -id | -| gpristine | git reset --hard && git clean -dffx | -| gcm | git checkout $(git_main_branch) | -| gcd | git checkout $(git_develop_branch) | -| gcmsg | git commit -m | -| gco | git checkout | -| gcor | git checkout --recurse-submodules | -| gcount | git shortlog -sn | -| gcp | git cherry-pick | -| gcpa | git cherry-pick --abort | -| gcpc | git cherry-pick --continue | -| gcs | git commit -S | -| gd | git diff | -| gdca | git diff --cached | -| gdcw | git diff --cached --word-diff | -| gdct | git describe --tags $(git rev-list --tags --max-count=1) | -| gds | git diff --staged | -| gdt | git diff-tree --no-commit-id --name-only -r | -| gdnolock | git diff $@ ":(exclude)package-lock.json" ":(exclude)*.lock" | -| gdup | git diff @{upstream} | -| gdv | git diff -w $@ \| view - | -| gdw | git diff --word-diff | -| gf | git fetch | -| gfa | git fetch --all --prune | -| gfg | git ls-files \| grep | -| gfo | git fetch origin | -| gg | git gui citool | -| gga | git gui citool --amend | -| ggf | git push --force origin $(current_branch) | -| ggfl | git push --force-with-lease origin $(current_branch) | -| ggl | git pull origin $(current_branch) | -| ggp | git push origin $(current_branch) | -| ggpnp | ggl && ggp | -| ggpull | git pull origin "$(git_current_branch)" | -| ggpur | ggu | -| ggpush | git push origin "$(git_current_branch)" | -| ggsup | git branch --set-upstream-to=origin/$(git_current_branch) | -| ggu | git pull --rebase origin $(current_branch) | -| gpsup | git push --set-upstream origin $(git_current_branch) | -| ghh | git help | -| gignore | git update-index --assume-unchanged | -| gignored | git ls-files -v \| grep "^[[:lower:]]" | -| git-svn-dcommit-push | git svn dcommit && git push github $(git_main_branch):svntrunk | -| gk | gitk --all --branches &! | -| gke | gitk --all $(git log -g --pretty=%h) &! | -| gl | git pull | -| glg | git log --stat | -| glgp | git log --stat -p | -| glgg | git log --graph | -| glgga | git log --graph --decorate --all | -| glgm | git log --graph --max-count=10 | -| glo | git log --oneline --decorate | -| glol | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' | -| glols | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --stat | -| glod | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' | -| glods | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' --date=short | -| glola | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --all | -| glog | git log --oneline --decorate --graph | -| gloga | git log --oneline --decorate --graph --all | -| glp | git log --pretty=\ | -| gm | git merge | -| gmom | git merge origin/$(git_main_branch) | -| gmtl | git mergetool --no-prompt | -| gmtlvim | git mergetool --no-prompt --tool=vimdiff | -| gmum | git merge upstream/$(git_main_branch) | -| gma | git merge --abort | -| gp | git push | -| gpd | git push --dry-run | -| gpf | git push --force-with-lease | -| gpf! | git push --force | -| gpoat | git push origin --all && git push origin --tags | -| gpr | git pull --rebase | -| gpu | git push upstream | -| gpv | git push -v | -| gr | git remote | -| gra | git remote add | -| grb | git rebase | -| grba | git rebase --abort | -| grbc | git rebase --continue | -| grbd | git rebase $(git_develop_branch) | -| grbi | git rebase -i | -| grbm | git rebase $(git_main_branch) | -| grbom | git rebase origin/$(git_main_branch) | -| grbo | git rebase --onto | -| grbs | git rebase --skip | -| grev | git revert | -| grh | git reset | -| grhh | git reset --hard | -| groh | git reset origin/$(git_current_branch) --hard | -| grm | git rm | -| grmc | git rm --cached | -| grmv | git remote rename | -| grrm | git remote remove | -| grs | git restore | -| grset | git remote set-url | -| grss | git restore --source | -| grst | git restore --staged | -| grt | cd "$(git rev-parse --show-toplevel \|\| echo .)" | -| gru | git reset -- | -| grup | git remote update | -| grv | git remote -v | -| gsb | git status -sb | -| gsd | git svn dcommit | -| gsh | git show | -| gsi | git submodule init | -| gsps | git show --pretty=short --show-signature | -| gsr | git svn rebase | -| gss | git status -s | -| gst | git status | -| gsta | git stash push | -| gsta | git stash save | -| gstaa | git stash apply | -| gstc | git stash clear | -| gstd | git stash drop | -| gstl | git stash list | -| gstp | git stash pop | -| gsts | git stash show --text | -| gstu | git stash --include-untracked | -| gstall | git stash --all | -| gsu | git submodule update | -| gsw | git switch | -| gswc | git switch -c | -| gswm | git switch $(git_main_branch) | -| gswd | git switch $(git_develop_branch) | -| gts | git tag -s | -| gtv | git tag \| sort -V | -| gtl | gtl(){ git tag --sort=-v:refname -n -l ${1}* }; noglob gtl | -| gunignore | git update-index --no-assume-unchanged | -| gunwip | git log -n 1 \| grep -q -c "\-\-wip\-\-" && git reset HEAD~1 | -| gup | git pull --rebase | -| gupv | git pull --rebase -v | -| gupa | git pull --rebase --autostash | -| gupav | git pull --rebase --autostash -v | -| gupom | git pull --rebase origin $(git_main_branch) | -| gupomi | git pull --rebase=interactive origin $(git_main_branch) | -| glum | git pull upstream $(git_main_branch) | -| gluc | git pull upstream $(git_current_branch) | -| gwch | git whatchanged -p --abbrev-commit --pretty=medium | -| gwip | git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign -m "--wip-- [skip ci]" | -| gam | git am | -| gamc | git am --continue | -| gams | git am --skip | -| gama | git am --abort | -| gamscp | git am --show-current-patch | +| Alias | Command | +| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------ | +| `grt` | `cd "$(git rev-parse --show-toplevel \|\| echo .)"` | +| `ggpnp` | `ggl && ggp` | +| `ggpur` | `ggu` | +| `g` | `git` | +| `ga` | `git add` | +| `gaa` | `git add --all` | +| `gapa` | `git add --patch` | +| `gau` | `git add --update` | +| `gav` | `git add --verbose` | +| `gwip` | `git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message "--wip-- [skip ci]"` | +| `gam` | `git am` | +| `gama` | `git am --abort` | +| `gamc` | `git am --continue` | +| `gamscp` | `git am --show-current-patch` | +| `gams` | `git am --skip` | +| `gap` | `git apply` | +| `gapt` | `git apply --3way` | +| `gbs` | `git bisect` | +| `gbsb` | `git bisect bad` | +| `gbsg` | `git bisect good` | +| `gbsn` | `git bisect new` | +| `gbso` | `git bisect old` | +| `gbsr` | `git bisect reset` | +| `gbss` | `git bisect start` | +| `gbl` | `git blame -w` | +| `gb` | `git branch` | +| `gba` | `git branch --all` | +| `gbd` | `git branch --delete` | +| `gbD` | `git branch --delete --force` | +| `gbgd` | `LANG=C git branch --no-color -vv \| grep ": gone\]" \| awk '"'"'{print $1}'"'"' \| xargs git branch -d` | +| `gbgD` | `LANG=C git branch --no-color -vv \| grep ": gone\]" \| awk '"'"'{print $1}'"'"' \| xargs git branch -D` | +| `gbm` | `git branch --move` | +| `gbnm` | `git branch --no-merged` | +| `gbr` | `git branch --remote` | +| `ggsup` | `git branch --set-upstream-to=origin/$(git_current_branch)` | +| `gbg` | `LANG=C git branch -vv \| grep ": gone\]"` | +| `gco` | `git checkout` | +| `gcor` | `git checkout --recurse-submodules` | +| `gcb` | `git checkout -b` | +| `gcB` | `git checkout -B` | +| `gcd` | `git checkout $(git_develop_branch)` | +| `gcm` | `git checkout $(git_main_branch)` | +| `gcp` | `git cherry-pick` | +| `gcpa` | `git cherry-pick --abort` | +| `gcpc` | `git cherry-pick --continue` | +| `gclean` | `git clean --interactive -d` | +| `gcl` | `git clone --recurse-submodules` | +| `gccd` | `git clone --recurse-submodules "$@" && cd "$(basename $\_ .git)"` | +| `gcam` | `git commit --all --message` | +| `gcas` | `git commit --all --signoff` | +| `gcasm` | `git commit --all --signoff --message` | +| `gcmsg` | `git commit --message` | +| `gcsm` | `git commit --signoff --message` | +| `gc` | `git commit --verbose` | +| `gca` | `git commit --verbose --all` | +| `gca!` | `git commit --verbose --all --amend` | +| `gcan!` | `git commit --verbose --all --no-edit --amend` | +| `gcans!` | `git commit --verbose --all --signoff --no-edit --amend` | +| `gc!` | `git commit --verbose --amend` | +| `gcn!` | `git commit --verbose --no-edit --amend` | +| `gcs` | `git commit -S` | +| `gcss` | `git commit -S -s` | +| `gcssm` | `git commit -S -s -m` | +| `gcf` | `git config --list` | +| `gdct` | `git describe --tags $(git rev-list --tags --max-count=1)` | +| `gd` | `git diff` | +| `gdca` | `git diff --cached` | +| `gdcw` | `git diff --cached --word-diff` | +| `gds` | `git diff --staged` | +| `gdw` | `git diff --word-diff` | +| `gdv` | `git diff -w "$@" \| view -` | +| `gdup` | `git diff @{upstream}` | +| `gdnolock` | `git diff $@ ":(exclude)package-lock.json" ":(exclude)\*.lock"` | +| `gdt` | `git diff-tree --no-commit-id --name-only -r` | +| `gf` | `git fetch` | +| `gfa` | `git fetch --all --prune` | +| `gfo` | `git fetch origin` | +| `gg` | `git gui citool` | +| `gga` | `git gui citool --amend` | +| `ghh` | `git help` | +| `glgg` | `git log --graph` | +| `glgga` | `git log --graph --decorate --all` | +| `glgm` | `git log --graph --max-count=10` | +| `glod` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset'` | +| `glods` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' --date=short` | +| `glol` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'` | +| `glola` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --all` | +| `glols` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --stat` | +| `glo` | `git log --oneline --decorate` | +| `glog` | `git log --oneline --decorate --graph` | +| `gloga` | `git log --oneline --decorate --graph --all` | +| `glp` | `git log --pretty=` | +| `glg` | `git log --stat` | +| `glgp` | `git log --stat --patch` | +| `gignored` | `git ls-files -v \| grep "^[[:lower:]]"` | +| `gfg` | `git ls-files \| grep` | +| `gm` | `git merge` | +| `gma` | `git merge --abort` | +| `gms` | `git merge --squash` | +| `gmom` | `git merge origin/$(git_main_branch)` | +| `gmum` | `git merge upstream/$(git_main_branch)` | +| `gmtl` | `git mergetool --no-prompt` | +| `gmtlvim` | `git mergetool --no-prompt --tool=vimdiff` | +| `gl` | `git pull` | +| `gpr` | `git pull --rebase` | +| `gprv` | `git pull --rebase -v` | +| `gpra` | `git pull --rebase --autostash` | +| `gprav` | `git pull --rebase --autostash -v` | +| `gprom` | `git pull --rebase origin $(git_main_branch)` | +| `gpromi` | `git pull --rebase=interactive origin $(git_main_branch)` | +| `ggpull` | `git pull origin "$(git_current_branch)"` | +| `ggl` | `git pull origin $(current_branch)` | +| `gluc` | `git pull upstream $(git_current_branch)` | +| `glum` | `git pull upstream $(git_main_branch)` | +| `gp` | `git push` | +| `gpd` | `git push --dry-run` | +| `gpf!` | `git push --force` | +| `ggf` | `git push --force origin $(current_branch)` | +| `gpf` | On Git >= 2.30: `git push --force-with-lease --force-if-includes` | +| `gpf` | On Git < 2.30: `git push --force-with-lease` | +| `ggfl` | `git push --force-with-lease origin $(current_branch)` | +| `gpsup` | `git push --set-upstream origin $(git_current_branch)` | +| `gpsupf` | On Git >= 2.30: `git push --set-upstream origin $(git_current_branch) --force-with-lease --force-if-includes` | +| `gpsupf` | On Git < 2.30: `git push --set-upstream origin $(git_current_branch) --force-with-lease` | +| `gpv` | `git push --verbose` | +| `gpoat` | `git push origin --all && git push origin --tags` | +| `gpod` | `git push origin --delete` | +| `ggpush` | `git push origin "$(git_current_branch)"` | +| `ggp` | `git push origin $(current_branch)` | +| `gpu` | `git push upstream` | +| `grb` | `git rebase` | +| `grba` | `git rebase --abort` | +| `grbc` | `git rebase --continue` | +| `grbi` | `git rebase --interactive` | +| `grbo` | `git rebase --onto` | +| `grbs` | `git rebase --skip` | +| `grbd` | `git rebase $(git_develop_branch)` | +| `grbm` | `git rebase $(git_main_branch)` | +| `grbom` | `git rebase origin/$(git_main_branch)` | +| `gr` | `git remote` | +| `grv` | `git remote --verbose` | +| `gra` | `git remote add` | +| `grrm` | `git remote remove` | +| `grmv` | `git remote rename` | +| `grset` | `git remote set-url` | +| `grup` | `git remote update` | +| `grh` | `git reset` | +| `gru` | `git reset --` | +| `grhh` | `git reset --hard` | +| `grhk` | `git reset --keep` | +| `grhs` | `git reset --soft` | +| `gpristine` | `git reset --hard && git clean -dffx` | +| `groh` | `git reset origin/$(git_current_branch) --hard` | +| `grs` | `git restore` | +| `grss` | `git restore --source` | +| `grst` | `git restore --staged` | +| `gunwip` | `git rev-list --max-count=1 --format="%s" HEAD \| grep -q "--wip--" && git reset HEAD~1` | +| `grev` | `git revert` | +| `grm` | `git rm` | +| `grmc` | `git rm --cached` | +| `gcount` | `git shortlog --summary -n` | +| `gsh` | `git show` | +| `gsps` | `git show --pretty=short --show-signature` | +| `gstall` | `git stash --all` | +| `gstu` | `git stash --include-untracked` | +| `gstaa` | `git stash apply` | +| `gstc` | `git stash clear` | +| `gstd` | `git stash drop` | +| `gstl` | `git stash list` | +| `gstp` | `git stash pop` | +| `gsta` | On Git >= 2.13: `git stash push` | +| `gsta` | On Git < 2.13: `git stash save` | +| `gsts` | `git stash show --patch` | +| `gst` | `git status` | +| `gss` | `git status --short` | +| `gsb` | `git status --short -b` | +| `gsi` | `git submodule init` | +| `gsu` | `git submodule update` | +| `gsd` | `git svn dcommit` | +| `git-svn-dcommit-push` | `git svn dcommit && git push github $(git_main_branch):svntrunk` | +| `gsr` | `git svn rebase` | +| `gsw` | `git switch` | +| `gswc` | `git switch -c` | +| `gswd` | `git switch $(git_develop_branch)` | +| `gswm` | `git switch $(git_main_branch)` | +| `gta` | `git tag --annotate` | +| `gts` | `git tag -s` | +| `gtv` | `git tag \| sort -V` | +| `gignore` | `git update-index --assume-unchanged` | +| `gunignore` | `git update-index --no-assume-unchanged` | +| `gwch` | `git whatchanged -p --abbrev-commit --pretty=medium` | +| `gwt` | `git worktree` | +| `gwtls` | `git worktree list` | +| `gwtmv` | `git worktree move` | +| `gwtrm` | `git worktree remove` | +| `gk` | `gitk --all --branches &!` | +| `gke` | `gitk --all $(git log --walk-reflogs --pretty=%h) &!` | +| `gtl` | `gtl(){ git tag --sort=-v:refname -n --list ${1}\* }; noglob gtl` | ### Main branch preference -Following the recent push for removing racially-charged words from our technical vocabulary, the git plugin favors using -a branch name other than `master`. In this case, we favor the shorter, neutral and descriptive term `main`. This means -that any aliases and functions that previously used `master`, will use `main` if that branch exists. We do this via the -function `git_main_branch`. +Following the recent push for removing racially-charged words from our technical vocabulary, the git plugin +favors using a branch name other than `master`. In this case, we favor the shorter, neutral and descriptive +term `main`. This means that any aliases and functions that previously used `master`, will use `main` if that +branch exists. We do this via the function `git_main_branch`. ### Deprecated aliases -These are aliases that have been removed, renamed, or otherwise modified in a way that may, or may not, receive further support. +These are aliases that have been removed, renamed, or otherwise modified in a way that may, or may not, +receive further support. -| Alias | Command | Modification | -| :----- | :----------------------------------------------------- | :----------------------------------------------------- | -| gap | `git add --patch` | new alias `gapa` | -| gcl | `git config --list` | new alias `gcf` | -| gdc | `git diff --cached` | new alias `gdca` | -| gdt | `git difftool` | no replacement | -| ggpull | `git pull origin $(current_branch)` | new alias `ggl` (`ggpull` still exists for now though) | -| ggpur | `git pull --rebase origin $(current_branch)` | new alias `ggu` (`ggpur` still exists for now though) | -| ggpush | `git push origin $(current_branch)` | new alias `ggp` (`ggpush` still exists for now though) | -| gk | `gitk --all --branches` | now aliased to `gitk --all --branches` | -| glg | `git log --stat --max-count = 10` | now aliased to `git log --stat --color` | -| glgg | `git log --graph --max-count = 10` | now aliased to `git log --graph --color` | -| gwc | `git whatchanged -p --abbrev-commit --pretty = medium` | new alias `gwch` | +| Alias | Command | Modification | +| :------- | :-------------------------------------------------------- | :-------------------------------------------------------- | +| `gap` | `git add --patch` | New alias: `gapa`. | +| `gcl` | `git config --list` | New alias: `gcf`. | +| `gdc` | `git diff --cached` | New alias: `gdca`. | +| `gdt` | `git difftool` | No replacement. | +| `ggpull` | `git pull origin $(current_branch)` | New alias: `ggl`. (`ggpull` still exists for now though.) | +| `ggpur` | `git pull --rebase origin $(current_branch)` | New alias: `ggu`. (`ggpur` still exists for now though.) | +| `ggpush` | `git push origin $(current_branch)` | New alias: `ggp`. (`ggpush` still exists for now though.) | +| `gk` | `gitk --all --branches` | Now aliased to `gitk --all --branches`. | +| `glg` | `git log --stat --max-count=10` | Now aliased to `git log --stat --color`. | +| `glgg` | `git log --graph --max-count=10` | Now aliased to `git log --graph --color`. | +| `gwc` | `git whatchanged -p --abbrev-commit --pretty = medium` | New alias: `gwch`. | +| `gup` | `git pull --rebase` | now alias `gpr` | +| `gupv` | `git pull --rebase -v` | now alias `gprv` | +| `gupa` | `git pull --rebase --autostash` | now alias `gpra` | +| `gupav` | `git pull --rebase --autostash -v` | now alias `gprav` | +| `gupom` | `git pull --rebase origin $(git_main_branch)` | now alias `gprom` | +| `gupomi` | `git pull --rebase=interactive origin $(git_main_branch)` | now alias `gpromi` | ## Functions ### Current -| Command | Description | -|:-----------------------|:---------------------------------------------------------------------------------------------------------| -| `grename ` | Rename `old` branch to `new`, including in origin remote | -| current_branch | Return the name of the current branch | -| git_current_user_name | Returns the `user.name` config value | -| git_current_user_email | Returns the `user.email` config value | -| git_main_branch | Returns the name of the main branch: `main` if it exists, `master` otherwise | -| git_develop_branch | Returns the name of the develop branch: `dev`, `devel`, `development` if they exist, `develop` otherwise | +| Command | Description | +| :----------------------- | :-------------------------------------------------------------------------------------------------------------- | +| `current_branch` | Returns the name of the current branch. | +| `git_current_user_email` | Returns the `user.email` config value. (Lives in `lib/git.zsh`.) | +| `git_current_user_name` | Returns the `user.name` config value. (Lives in `lib/git.zsh`.) | +| `git_develop_branch` | Returns the name of the “development” branch: `dev`, `devel`, `development` if they exist, `develop` otherwise. | +| `git_main_branch` | Returns the name of the main branch: `main` if it exists, `master` otherwise. | +| `grename ` | Renames branch `` to ``, including on the origin remote. | +| `gbda` | Deletes all merged branches | +| `gbds` | Deletes all squash-merged branches (**Note: performance degrades with number of branches**) | ### Work in Progress (WIP) -These features allow to pause a branch development and switch to another one (_"Work in Progress"_, or wip). When you want to go back to work, just unwip it. +These features allow you to pause developing one branch and switch to another one (_"Work in Progress"_, or +“wip”). When you want to go back to work, just “unwip” it. -| Command | Description | -|:-----------------|:------------------------------------------------| -| work_in_progress | Echoes a warning if the current branch is a wip | -| gwip | Commit wip branch | -| gunwip | Uncommit wip branch | +| Command | Description | +| :----------------- | :---------------------------------------------- | +| `gwip` | Commit wip branch | +| `gunwip` | Uncommit wip branch | +| `gunwipall` | Uncommit all recent `--wip--` commits | +| `work_in_progress` | Echoes a warning if the current branch is a wip | + +Note that `gwip` and `gunwip` are aliases, but are also documented here to group all related WIP features. ### Deprecated functions -| Command | Description | Reason | -|:-----------------------|:----------------------------------------|:----------------------------------------------------------------| -| current_repository | Return the names of the current remotes | Didn't work properly. Use `git remote -v` instead (`grv` alias) | +| Command | Description | Reason | +| :------------------- | :-------------------------------------- | :--------------------------------------------------------------- | +| `current_repository` | Return the names of the current remotes | Didn't work properly. Use `git remote -v` instead (`grv` alias). | diff --git a/plugins/git/git.plugin.zsh b/plugins/git/git.plugin.zsh index f25453bc1..bee9eb67d 100644 --- a/plugins/git/git.plugin.zsh +++ b/plugins/git/git.plugin.zsh @@ -3,7 +3,9 @@ autoload -Uz is-at-least git_version="${${(As: :)$(git version 2>/dev/null)}[3]}" # -# Functions +# Functions Current +# (sorted alphabetically by function name) +# (order should follow README) # # The name of the current branch @@ -14,313 +16,37 @@ function current_branch() { git_current_branch } -# Pretty log messages -function _git_log_prettily(){ - if ! [ -z $1 ]; then - git log --pretty=$1 - fi -} -compdef _git _git_log_prettily=git-log +# Check for develop and similarly named branches +function git_develop_branch() { + command git rev-parse --git-dir &>/dev/null || return + local branch + for branch in dev devel develop development; do + if command git show-ref -q --verify refs/heads/$branch; then + echo $branch + return 0 + fi + done -# Warn if the current branch is a WIP -function work_in_progress() { - command git -c log.showSignature=false log -n 1 2>/dev/null | grep -q -- "--wip--" && echo "WIP!!" + echo develop + return 1 } # Check if main exists and use instead of master function git_main_branch() { command git rev-parse --git-dir &>/dev/null || return local ref - for ref in refs/{heads,remotes/{origin,upstream}}/{main,trunk}; do + for ref in refs/{heads,remotes/{origin,upstream}}/{main,trunk,mainline,default,master}; do if command git show-ref -q --verify $ref; then echo ${ref:t} - return + return 0 fi done + + # If no main branch was found, fall back to master but return error echo master + return 1 } -# Check for develop and similarly named branches -function git_develop_branch() { - command git rev-parse --git-dir &>/dev/null || return - local branch - for branch in dev devel development; do - if command git show-ref -q --verify refs/heads/$branch; then - echo $branch - return - fi - done - echo develop -} - -# -# Aliases -# (sorted alphabetically) -# - -alias g='git' - -alias ga='git add' -alias gaa='git add --all' -alias gapa='git add --patch' -alias gau='git add --update' -alias gav='git add --verbose' -alias gap='git apply' -alias gapt='git apply --3way' - -alias gb='git branch' -alias gba='git branch -a' -alias gbd='git branch -d' -alias gbda='git branch --no-color --merged | command grep -vE "^([+*]|\s*($(git_main_branch)|$(git_develop_branch))\s*$)" | command xargs git branch -d 2>/dev/null' -alias gbD='git branch -D' -alias gbl='git blame -b -w' -alias gbnm='git branch --no-merged' -alias gbr='git branch --remote' -alias gbs='git bisect' -alias gbsb='git bisect bad' -alias gbsg='git bisect good' -alias gbsr='git bisect reset' -alias gbss='git bisect start' - -alias gc='git commit -v' -alias gc!='git commit -v --amend' -alias gcn!='git commit -v --no-edit --amend' -alias gca='git commit -v -a' -alias gca!='git commit -v -a --amend' -alias gcan!='git commit -v -a --no-edit --amend' -alias gcans!='git commit -v -a -s --no-edit --amend' -alias gcam='git commit -a -m' -alias gcsm='git commit -s -m' -alias gcas='git commit -a -s' -alias gcasm='git commit -a -s -m' -alias gcb='git checkout -b' -alias gcf='git config --list' - -function gccd() { - command git clone --recurse-submodules "$@" - [[ -d "$_" ]] && cd "$_" || cd "${${_:t}%.git}" -} -compdef _git gccd=git-clone - -alias gcl='git clone --recurse-submodules' -alias gclean='git clean -id' -alias gpristine='git reset --hard && git clean -dffx' -alias gcm='git checkout $(git_main_branch)' -alias gcd='git checkout $(git_develop_branch)' -alias gcmsg='git commit -m' -alias gco='git checkout' -alias gcor='git checkout --recurse-submodules' -alias gcount='git shortlog -sn' -alias gcp='git cherry-pick' -alias gcpa='git cherry-pick --abort' -alias gcpc='git cherry-pick --continue' -alias gcs='git commit -S' -alias gcss='git commit -S -s' -alias gcssm='git commit -S -s -m' - -alias gd='git diff' -alias gdca='git diff --cached' -alias gdcw='git diff --cached --word-diff' -alias gdct='git describe --tags $(git rev-list --tags --max-count=1)' -alias gds='git diff --staged' -alias gdt='git diff-tree --no-commit-id --name-only -r' -alias gdup='git diff @{upstream}' -alias gdw='git diff --word-diff' - -function gdnolock() { - git diff "$@" ":(exclude)package-lock.json" ":(exclude)*.lock" -} -compdef _git gdnolock=git-diff - -function gdv() { git diff -w "$@" | view - } -compdef _git gdv=git-diff - -alias gf='git fetch' -# --jobs= was added in git 2.8 -is-at-least 2.8 "$git_version" \ - && alias gfa='git fetch --all --prune --jobs=10' \ - || alias gfa='git fetch --all --prune' -alias gfo='git fetch origin' - -alias gfg='git ls-files | grep' - -alias gg='git gui citool' -alias gga='git gui citool --amend' - -function ggf() { - [[ "$#" != 1 ]] && local b="$(git_current_branch)" - git push --force origin "${b:=$1}" -} -compdef _git ggf=git-checkout -function ggfl() { - [[ "$#" != 1 ]] && local b="$(git_current_branch)" - git push --force-with-lease origin "${b:=$1}" -} -compdef _git ggfl=git-checkout - -function ggl() { - if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then - git pull origin "${*}" - else - [[ "$#" == 0 ]] && local b="$(git_current_branch)" - git pull origin "${b:=$1}" - fi -} -compdef _git ggl=git-checkout - -function ggp() { - if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then - git push origin "${*}" - else - [[ "$#" == 0 ]] && local b="$(git_current_branch)" - git push origin "${b:=$1}" - fi -} -compdef _git ggp=git-checkout - -function ggpnp() { - if [[ "$#" == 0 ]]; then - ggl && ggp - else - ggl "${*}" && ggp "${*}" - fi -} -compdef _git ggpnp=git-checkout - -function ggu() { - [[ "$#" != 1 ]] && local b="$(git_current_branch)" - git pull --rebase origin "${b:=$1}" -} -compdef _git ggu=git-checkout - -alias ggpur='ggu' -alias ggpull='git pull origin "$(git_current_branch)"' -alias ggpush='git push origin "$(git_current_branch)"' - -alias ggsup='git branch --set-upstream-to=origin/$(git_current_branch)' -alias gpsup='git push --set-upstream origin $(git_current_branch)' - -alias ghh='git help' - -alias gignore='git update-index --assume-unchanged' -alias gignored='git ls-files -v | grep "^[[:lower:]]"' -alias git-svn-dcommit-push='git svn dcommit && git push github $(git_main_branch):svntrunk' - -alias gk='\gitk --all --branches &!' -alias gke='\gitk --all $(git log -g --pretty=%h) &!' - -alias gl='git pull' -alias glg='git log --stat' -alias glgp='git log --stat -p' -alias glgg='git log --graph' -alias glgga='git log --graph --decorate --all' -alias glgm='git log --graph --max-count=10' -alias glo='git log --oneline --decorate' -alias glol="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'" -alias glols="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --stat" -alias glod="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset'" -alias glods="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' --date=short" -alias glola="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --all" -alias glog='git log --oneline --decorate --graph' -alias gloga='git log --oneline --decorate --graph --all' -alias glp="_git_log_prettily" - -alias gm='git merge' -alias gmom='git merge origin/$(git_main_branch)' -alias gmtl='git mergetool --no-prompt' -alias gmtlvim='git mergetool --no-prompt --tool=vimdiff' -alias gmum='git merge upstream/$(git_main_branch)' -alias gma='git merge --abort' - -alias gp='git push' -alias gpd='git push --dry-run' -alias gpf='git push --force-with-lease' -alias gpf!='git push --force' -alias gpoat='git push origin --all && git push origin --tags' -alias gpr='git pull --rebase' -alias gpu='git push upstream' -alias gpv='git push -v' - -alias gr='git remote' -alias gra='git remote add' -alias grb='git rebase' -alias grba='git rebase --abort' -alias grbc='git rebase --continue' -alias grbd='git rebase $(git_develop_branch)' -alias grbi='git rebase -i' -alias grbm='git rebase $(git_main_branch)' -alias grbom='git rebase origin/$(git_main_branch)' -alias grbo='git rebase --onto' -alias grbs='git rebase --skip' -alias grev='git revert' -alias grh='git reset' -alias grhh='git reset --hard' -alias groh='git reset origin/$(git_current_branch) --hard' -alias grm='git rm' -alias grmc='git rm --cached' -alias grmv='git remote rename' -alias grrm='git remote remove' -alias grs='git restore' -alias grset='git remote set-url' -alias grss='git restore --source' -alias grst='git restore --staged' -alias grt='cd "$(git rev-parse --show-toplevel || echo .)"' -alias gru='git reset --' -alias grup='git remote update' -alias grv='git remote -v' - -alias gsb='git status -sb' -alias gsd='git svn dcommit' -alias gsh='git show' -alias gsi='git submodule init' -alias gsps='git show --pretty=short --show-signature' -alias gsr='git svn rebase' -alias gss='git status -s' -alias gst='git status' - -# use the default stash push on git 2.13 and newer -is-at-least 2.13 "$git_version" \ - && alias gsta='git stash push' \ - || alias gsta='git stash save' - -alias gstaa='git stash apply' -alias gstc='git stash clear' -alias gstd='git stash drop' -alias gstl='git stash list' -alias gstp='git stash pop' -alias gsts='git stash show --text' -alias gstu='gsta --include-untracked' -alias gstall='git stash --all' -alias gsu='git submodule update' -alias gsw='git switch' -alias gswc='git switch -c' -alias gswm='git switch $(git_main_branch)' -alias gswd='git switch $(git_develop_branch)' - -alias gts='git tag -s' -alias gtv='git tag | sort -V' -alias gtl='gtl(){ git tag --sort=-v:refname -n -l "${1}*" }; noglob gtl' - -alias gunignore='git update-index --no-assume-unchanged' -alias gunwip='git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1' -alias gup='git pull --rebase' -alias gupv='git pull --rebase -v' -alias gupa='git pull --rebase --autostash' -alias gupav='git pull --rebase --autostash -v' -alias gupom='git pull --rebase origin $(git_main_branch)' -alias gupomi='git pull --rebase=interactive origin $(git_main_branch)' -alias glum='git pull upstream $(git_main_branch)' -alias gluc='git pull upstream $(git_current_branch)' - -alias gwch='git whatchanged -p --abbrev-commit --pretty=medium' -alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign -m "--wip-- [skip ci]"' - -alias gam='git am' -alias gamc='git am --continue' -alias gams='git am --skip' -alias gama='git am --abort' -alias gamscp='git am --show-current-patch' - function grename() { if [[ -z "$1" || -z "$2" ]]; then echo "Usage: $0 old_branch new_branch" @@ -335,4 +61,357 @@ function grename() { fi } +# +# Functions Work in Progress (WIP) +# (sorted alphabetically by function name) +# (order should follow README) +# + +# Similar to `gunwip` but recursive "Unwips" all recent `--wip--` commits not just the last one +function gunwipall() { + local _commit=$(git log --grep='--wip--' --invert-grep --max-count=1 --format=format:%H) + + # Check if a commit without "--wip--" was found and it's not the same as HEAD + if [[ "$_commit" != "$(git rev-parse HEAD)" ]]; then + git reset $_commit || return 1 + fi +} + +# Warn if the current branch is a WIP +function work_in_progress() { + command git -c log.showSignature=false log -n 1 2>/dev/null | grep -q -- "--wip--" && echo "WIP!!" +} + +# +# Aliases +# (sorted alphabetically by command) +# (order should follow README) +# (in some cases force the alisas order to match README, like for example gke and gk) +# + +alias grt='cd "$(git rev-parse --show-toplevel || echo .)"' + +function ggpnp() { + if [[ "$#" == 0 ]]; then + ggl && ggp + else + ggl "${*}" && ggp "${*}" + fi +} +compdef _git ggpnp=git-checkout + +alias ggpur='ggu' +alias g='git' +alias ga='git add' +alias gaa='git add --all' +alias gapa='git add --patch' +alias gau='git add --update' +alias gav='git add --verbose' +alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message "--wip-- [skip ci]"' +alias gam='git am' +alias gama='git am --abort' +alias gamc='git am --continue' +alias gamscp='git am --show-current-patch' +alias gams='git am --skip' +alias gap='git apply' +alias gapt='git apply --3way' +alias gbs='git bisect' +alias gbsb='git bisect bad' +alias gbsg='git bisect good' +alias gbsn='git bisect new' +alias gbso='git bisect old' +alias gbsr='git bisect reset' +alias gbss='git bisect start' +alias gbl='git blame -w' +alias gb='git branch' +alias gba='git branch --all' +alias gbd='git branch --delete' +alias gbD='git branch --delete --force' + +function gbda() { + git branch --no-color --merged | command grep -vE "^([+*]|\s*($(git_main_branch)|$(git_develop_branch))\s*$)" | command xargs git branch --delete 2>/dev/null +} + +# Copied and modified from James Roeder (jmaroeder) under MIT License +# https://github.com/jmaroeder/plugin-git/blob/216723ef4f9e8dde399661c39c80bdf73f4076c4/functions/gbda.fish +function gbds() { + local default_branch=$(git_main_branch) + (( ! $? )) || default_branch=$(git_develop_branch) + + git for-each-ref refs/heads/ "--format=%(refname:short)" | \ + while read branch; do + local merge_base=$(git merge-base $default_branch $branch) + if [[ $(git cherry $default_branch $(git commit-tree $(git rev-parse $branch\^{tree}) -p $merge_base -m _)) = -* ]]; then + git branch -D $branch + fi + done +} + +alias gbgd='LANG=C git branch --no-color -vv | grep ": gone\]" | awk '"'"'{print $1}'"'"' | xargs git branch -d' +alias gbgD='LANG=C git branch --no-color -vv | grep ": gone\]" | awk '"'"'{print $1}'"'"' | xargs git branch -D' +alias gbm='git branch --move' +alias gbnm='git branch --no-merged' +alias gbr='git branch --remote' +alias ggsup='git branch --set-upstream-to=origin/$(git_current_branch)' +alias gbg='LANG=C git branch -vv | grep ": gone\]"' +alias gco='git checkout' +alias gcor='git checkout --recurse-submodules' +alias gcb='git checkout -b' +alias gcB='git checkout -B' +alias gcd='git checkout $(git_develop_branch)' +alias gcm='git checkout $(git_main_branch)' +alias gcp='git cherry-pick' +alias gcpa='git cherry-pick --abort' +alias gcpc='git cherry-pick --continue' +alias gclean='git clean --interactive -d' +alias gcl='git clone --recurse-submodules' + +function gccd() { + setopt localoptions extendedglob + + # get repo URI from args based on valid formats: https://git-scm.com/docs/git-clone#URLS + local repo="${${@[(r)(ssh://*|git://*|ftp(s)#://*|http(s)#://*|*@*)(.git/#)#]}:-$_}" + + # clone repository and exit if it fails + command git clone --recurse-submodules "$@" || return + + # if last arg passed was a directory, that's where the repo was cloned + # otherwise parse the repo URI and use the last part as the directory + [[ -d "$_" ]] && cd "$_" || cd "${${repo:t}%.git/#}" +} +compdef _git gccd=git-clone + +alias gcam='git commit --all --message' +alias gcas='git commit --all --signoff' +alias gcasm='git commit --all --signoff --message' +alias gcs='git commit --gpg-sign' +alias gcss='git commit --gpg-sign --signoff' +alias gcssm='git commit --gpg-sign --signoff --message' +alias gcmsg='git commit --message' +alias gcsm='git commit --signoff --message' +alias gc='git commit --verbose' +alias gca='git commit --verbose --all' +alias gca!='git commit --verbose --all --amend' +alias gcan!='git commit --verbose --all --no-edit --amend' +alias gcans!='git commit --verbose --all --signoff --no-edit --amend' +alias gc!='git commit --verbose --amend' +alias gcn!='git commit --verbose --no-edit --amend' +alias gcf='git config --list' +alias gdct='git describe --tags $(git rev-list --tags --max-count=1)' +alias gd='git diff' +alias gdca='git diff --cached' +alias gdcw='git diff --cached --word-diff' +alias gds='git diff --staged' +alias gdw='git diff --word-diff' + +function gdv() { git diff -w "$@" | view - } +compdef _git gdv=git-diff + +alias gdup='git diff @{upstream}' + +function gdnolock() { + git diff "$@" ":(exclude)package-lock.json" ":(exclude)*.lock" +} +compdef _git gdnolock=git-diff + +alias gdt='git diff-tree --no-commit-id --name-only -r' +alias gf='git fetch' +# --jobs= was added in git 2.8 +is-at-least 2.8 "$git_version" \ + && alias gfa='git fetch --all --prune --jobs=10' \ + || alias gfa='git fetch --all --prune' +alias gfo='git fetch origin' +alias gg='git gui citool' +alias gga='git gui citool --amend' +alias ghh='git help' +alias glgg='git log --graph' +alias glgga='git log --graph --decorate --all' +alias glgm='git log --graph --max-count=10' +alias glods='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset" --date=short' +alias glod='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset"' +alias glola='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset" --all' +alias glols='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset" --stat' +alias glol='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset"' +alias glo='git log --oneline --decorate' +alias glog='git log --oneline --decorate --graph' +alias gloga='git log --oneline --decorate --graph --all' + +# Pretty log messages +function _git_log_prettily(){ + if ! [ -z $1 ]; then + git log --pretty=$1 + fi +} +compdef _git _git_log_prettily=git-log + +alias glp='_git_log_prettily' +alias glg='git log --stat' +alias glgp='git log --stat --patch' +alias gignored='git ls-files -v | grep "^[[:lower:]]"' +alias gfg='git ls-files | grep' +alias gm='git merge' +alias gma='git merge --abort' +alias gms="git merge --squash" +alias gmom='git merge origin/$(git_main_branch)' +alias gmum='git merge upstream/$(git_main_branch)' +alias gmtl='git mergetool --no-prompt' +alias gmtlvim='git mergetool --no-prompt --tool=vimdiff' + +alias gl='git pull' +alias gpr='git pull --rebase' +alias gprv='git pull --rebase -v' +alias gpra='git pull --rebase --autostash' +alias gprav='git pull --rebase --autostash -v' + +function ggu() { + [[ "$#" != 1 ]] && local b="$(git_current_branch)" + git pull --rebase origin "${b:=$1}" +} +compdef _git ggu=git-checkout + +alias gprom='git pull --rebase origin $(git_main_branch)' +alias gpromi='git pull --rebase=interactive origin $(git_main_branch)' +alias ggpull='git pull origin "$(git_current_branch)"' + +function ggl() { + if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then + git pull origin "${*}" + else + [[ "$#" == 0 ]] && local b="$(git_current_branch)" + git pull origin "${b:=$1}" + fi +} +compdef _git ggl=git-checkout + +alias gluc='git pull upstream $(git_current_branch)' +alias glum='git pull upstream $(git_main_branch)' +alias gp='git push' +alias gpd='git push --dry-run' + +function ggf() { + [[ "$#" != 1 ]] && local b="$(git_current_branch)" + git push --force origin "${b:=$1}" +} +compdef _git ggf=git-checkout + +alias gpf!='git push --force' +is-at-least 2.30 "$git_version" \ + && alias gpf='git push --force-with-lease --force-if-includes' \ + || alias gpf='git push --force-with-lease' + +function ggfl() { + [[ "$#" != 1 ]] && local b="$(git_current_branch)" + git push --force-with-lease origin "${b:=$1}" +} +compdef _git ggfl=git-checkout + +alias gpsup='git push --set-upstream origin $(git_current_branch)' +is-at-least 2.30 "$git_version" \ + && alias gpsupf='git push --set-upstream origin $(git_current_branch) --force-with-lease --force-if-includes' \ + || alias gpsupf='git push --set-upstream origin $(git_current_branch) --force-with-lease' +alias gpv='git push --verbose' +alias gpoat='git push origin --all && git push origin --tags' +alias gpod='git push origin --delete' +alias ggpush='git push origin "$(git_current_branch)"' + +function ggp() { + if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then + git push origin "${*}" + else + [[ "$#" == 0 ]] && local b="$(git_current_branch)" + git push origin "${b:=$1}" + fi +} +compdef _git ggp=git-checkout + +alias gpu='git push upstream' +alias grb='git rebase' +alias grba='git rebase --abort' +alias grbc='git rebase --continue' +alias grbi='git rebase --interactive' +alias grbo='git rebase --onto' +alias grbs='git rebase --skip' +alias grbd='git rebase $(git_develop_branch)' +alias grbm='git rebase $(git_main_branch)' +alias grbom='git rebase origin/$(git_main_branch)' +alias gr='git remote' +alias grv='git remote --verbose' +alias gra='git remote add' +alias grrm='git remote remove' +alias grmv='git remote rename' +alias grset='git remote set-url' +alias grup='git remote update' +alias grh='git reset' +alias gru='git reset --' +alias grhh='git reset --hard' +alias grhk='git reset --keep' +alias grhs='git reset --soft' +alias gpristine='git reset --hard && git clean --force -dfx' +alias groh='git reset origin/$(git_current_branch) --hard' +alias grs='git restore' +alias grss='git restore --source' +alias grst='git restore --staged' +alias gunwip='git rev-list --max-count=1 --format="%s" HEAD | grep -q "\--wip--" && git reset HEAD~1' +alias grev='git revert' +alias grm='git rm' +alias grmc='git rm --cached' +alias gcount='git shortlog --summary --numbered' +alias gsh='git show' +alias gsps='git show --pretty=short --show-signature' +alias gstall='git stash --all' +alias gstaa='git stash apply' +alias gstc='git stash clear' +alias gstd='git stash drop' +alias gstl='git stash list' +alias gstp='git stash pop' +# use the default stash push on git 2.13 and newer +is-at-least 2.13 "$git_version" \ + && alias gsta='git stash push' \ + || alias gsta='git stash save' +alias gsts='git stash show --patch' +alias gst='git status' +alias gss='git status --short' +alias gsb='git status --short --branch' +alias gsi='git submodule init' +alias gsu='git submodule update' +alias gsd='git svn dcommit' +alias git-svn-dcommit-push='git svn dcommit && git push github $(git_main_branch):svntrunk' +alias gsr='git svn rebase' +alias gsw='git switch' +alias gswc='git switch --create' +alias gswd='git switch $(git_develop_branch)' +alias gswm='git switch $(git_main_branch)' +alias gta='git tag --annotate' +alias gts='git tag --sign' +alias gtv='git tag | sort -V' +alias gignore='git update-index --assume-unchanged' +alias gunignore='git update-index --no-assume-unchanged' +alias gwch='git whatchanged -p --abbrev-commit --pretty=medium' +alias gwt='git worktree' +alias gwta='git worktree add' +alias gwtls='git worktree list' +alias gwtmv='git worktree move' +alias gwtrm='git worktree remove' +alias gstu='gsta --include-untracked' +alias gtl='gtl(){ git tag --sort=-v:refname -n --list "${1}*" }; noglob gtl' +alias gk='\gitk --all --branches &!' +alias gke='\gitk --all $(git log --walk-reflogs --pretty=%h) &!' + unset git_version + +# Logic for adding warnings on deprecated aliases +local old_alias new_alias +for old_alias new_alias ( + # TODO(2023-10-19): remove deprecated `git pull --rebase` aliases + gup gpr + gupv gprv + gupa gpra + gupav gprav + gupom gprom + gupomi gpromi +); do + aliases[$old_alias]=" + print -Pu2 \"%F{yellow}[oh-my-zsh] '%F{red}${old_alias}%F{yellow}' is a deprecated alias, using '%F{green}${new_alias}%F{yellow}' instead.%f\" + $new_alias" +done +unset old_alias new_alias diff --git a/plugins/gitfast/git-completion.bash b/plugins/gitfast/git-completion.bash index dd06b5048..9a2045f26 100644 --- a/plugins/gitfast/git-completion.bash +++ b/plugins/gitfast/git-completion.bash @@ -58,6 +58,12 @@ # # When set to "1" suggest all options, including options which are # typically hidden (e.g. '--allow-empty' for 'git commit'). +# +# GIT_COMPLETION_IGNORE_CASE +# +# When set, uses for-each-ref '--ignore-case' to find refs that match +# case insensitively, even on systems with case sensitive file systems +# (e.g., completing tag name "FOO" on "git checkout f"). # The following functions are meant to modify COMPREPLY, which should not be # modified directly. The purpose is to localize the modifications so it's @@ -320,116 +326,6 @@ else unset $(compgen -v __gitcomp_builtin_) fi -__gitcomp_builtin_add_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-removal --refresh --ignore-errors --ignore-missing --sparse --chmod= --pathspec-from-file= --pathspec-file-nul --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit --no-force --no-update --no-renormalize --no-intent-to-add --no-all --no-ignore-removal --no-refresh --no-ignore-errors --no-ignore-missing --no-sparse --no-chmod --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_am_default=" --interactive --3way --quiet --signoff --utf8 --keep --keep-non-patch --message-id --keep-cr --no-keep-cr --scissors --quoted-cr= --whitespace= --ignore-space-change --ignore-whitespace --directory= --exclude= --include= --patch-format= --reject --resolvemsg= --continue --resolved --skip --abort --quit --show-current-patch --allow-empty --committer-date-is-author-date --ignore-date --rerere-autoupdate --gpg-sign --empty= -- --no-interactive --no-3way --no-quiet --no-signoff --no-utf8 --no-keep --no-keep-non-patch --no-message-id --no-scissors --no-whitespace --no-ignore-space-change --no-ignore-whitespace --no-directory --no-exclude --no-include --no-patch-format --no-reject --no-resolvemsg --no-committer-date-is-author-date --no-ignore-date --no-rerere-autoupdate --no-gpg-sign" -__gitcomp_builtin_apply_default=" --exclude= --include= --no-add --stat --numstat --summary --check --index --intent-to-add --cached --apply --3way --build-fake-ancestor= --whitespace= --ignore-space-change --ignore-whitespace --reverse --unidiff-zero --reject --allow-overlap --verbose --quiet --inaccurate-eof --recount --directory= --allow-empty --add -- --no-stat --no-numstat --no-summary --no-check --no-index --no-intent-to-add --no-cached --no-apply --no-3way --no-build-fake-ancestor --no-whitespace --no-ignore-space-change --no-ignore-whitespace --no-reverse --no-unidiff-zero --no-reject --no-allow-overlap --no-verbose --no-quiet --no-inaccurate-eof --no-recount --no-directory --no-allow-empty" -__gitcomp_builtin_archive_default=" --output= --remote= --exec= --no-output -- --no-remote --no-exec" -__gitcomp_builtin_bisect__helper_default=" --bisect-reset --bisect-next-check --bisect-terms --bisect-start --bisect-next --bisect-state --bisect-log --bisect-replay --bisect-skip --bisect-visualize --bisect-run --no-log --log" -__gitcomp_builtin_blame_default=" --incremental --root --show-stats --progress --score-debug --show-name --show-number --porcelain --line-porcelain --show-email --ignore-rev= --ignore-revs-file= --color-lines --color-by-age --minimal --contents= --abbrev --no-incremental -- --no-root --no-show-stats --no-progress --no-score-debug --no-show-name --no-show-number --no-porcelain --no-line-porcelain --no-show-email --no-ignore-rev --no-ignore-revs-file --no-color-lines --no-color-by-age --no-minimal --no-contents --no-abbrev" -__gitcomp_builtin_branch_default=" --verbose --quiet --track --set-upstream-to= --unset-upstream --color --remotes --contains --no-contains --abbrev --all --delete --move --copy --list --show-current --create-reflog --edit-description --merged --no-merged --column --sort= --points-at= --ignore-case --recurse-submodules --format= -- --no-verbose --no-quiet --no-track --no-set-upstream-to --no-unset-upstream --no-color --no-remotes --no-abbrev --no-all --no-delete --no-move --no-copy --no-list --no-show-current --no-create-reflog --no-edit-description --no-column --no-sort --no-points-at --no-ignore-case --no-recurse-submodules --no-format" -__gitcomp_builtin_bugreport_default=" --output-directory= --suffix= --no-output-directory -- --no-suffix" -__gitcomp_builtin_cat_file_default=" --allow-unknown-type --batch --batch-check --batch-command --batch-all-objects --buffer --follow-symlinks --unordered --textconv --filters --path= --no-allow-unknown-type -- --no-buffer --no-follow-symlinks --no-unordered --no-path" -__gitcomp_builtin_check_attr_default=" --all --cached --stdin --no-all -- --no-cached --no-stdin" -__gitcomp_builtin_check_ignore_default=" --quiet --verbose --stdin --non-matching --no-index --index -- --no-quiet --no-verbose --no-stdin --no-non-matching" -__gitcomp_builtin_check_mailmap_default=" --stdin --no-stdin" -__gitcomp_builtin_checkout_default=" --guess --overlay --quiet --recurse-submodules --progress --merge --conflict= --detach --track --orphan= --ignore-other-worktrees --ours --theirs --patch --ignore-skip-worktree-bits --pathspec-from-file= --pathspec-file-nul --no-guess -- --no-overlay --no-quiet --no-recurse-submodules --no-progress --no-merge --no-conflict --no-detach --no-track --no-orphan --no-ignore-other-worktrees --no-patch --no-ignore-skip-worktree-bits --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_checkout__worker_default=" --prefix= --no-prefix" -__gitcomp_builtin_checkout_index_default=" --all --ignore-skip-worktree-bits --force --quiet --no-create --index --stdin --temp --prefix= --stage= --create -- --no-all --no-ignore-skip-worktree-bits --no-force --no-quiet --no-index --no-stdin --no-temp --no-prefix" -__gitcomp_builtin_cherry_default=" --abbrev --verbose --no-abbrev -- --no-verbose" -__gitcomp_builtin_cherry_pick_default=" --quit --continue --abort --skip --cleanup= --no-commit --edit --signoff --mainline= --rerere-autoupdate --strategy= --strategy-option= --gpg-sign --ff --allow-empty --allow-empty-message --keep-redundant-commits --commit -- --no-cleanup --no-edit --no-signoff --no-mainline --no-rerere-autoupdate --no-strategy --no-strategy-option --no-gpg-sign --no-ff --no-allow-empty --no-allow-empty-message --no-keep-redundant-commits" -__gitcomp_builtin_clean_default=" --quiet --dry-run --interactive --exclude= --no-quiet -- --no-dry-run --no-interactive" -__gitcomp_builtin_clone_default=" --verbose --quiet --progress --reject-shallow --no-checkout --bare --mirror --local --no-hardlinks --shared --recurse-submodules --jobs= --template= --reference= --reference-if-able= --dissociate --origin= --branch= --upload-pack= --depth= --shallow-since= --shallow-exclude= --single-branch --no-tags --shallow-submodules --separate-git-dir= --config= --server-option= --ipv4 --ipv6 --filter= --also-filter-submodules --remote-submodules --sparse --checkout --hardlinks --tags -- --no-verbose --no-quiet --no-progress --no-reject-shallow --no-bare --no-mirror --no-local --no-shared --no-recurse-submodules --no-recursive --no-jobs --no-template --no-reference --no-reference-if-able --no-dissociate --no-origin --no-branch --no-upload-pack --no-depth --no-shallow-since --no-shallow-exclude --no-single-branch --no-shallow-submodules --no-separate-git-dir --no-config --no-server-option --no-ipv4 --no-ipv6 --no-filter --no-also-filter-submodules --no-remote-submodules --no-sparse" -__gitcomp_builtin_column_default=" --command= --mode --raw-mode= --width= --indent= --nl= --padding= --no-command -- --no-mode --no-raw-mode --no-width --no-indent --no-nl --no-padding" -__gitcomp_builtin_commit_default=" --quiet --verbose --file= --author= --date= --message= --reedit-message= --reuse-message= --fixup= --squash= --reset-author --trailer= --signoff --template= --edit --cleanup= --status --gpg-sign --all --include --interactive --patch --only --no-verify --dry-run --short --branch --ahead-behind --porcelain --long --null --amend --no-post-rewrite --untracked-files --pathspec-from-file= --pathspec-file-nul --verify --post-rewrite -- --no-quiet --no-verbose --no-file --no-author --no-date --no-message --no-reedit-message --no-reuse-message --no-fixup --no-squash --no-reset-author --no-signoff --no-template --no-edit --no-cleanup --no-status --no-gpg-sign --no-all --no-include --no-interactive --no-patch --no-only --no-dry-run --no-short --no-branch --no-ahead-behind --no-porcelain --no-long --no-null --no-amend --no-untracked-files --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_commit_graph_default=" --object-dir= --no-object-dir" -__gitcomp_builtin_config_default=" --global --system --local --worktree --file= --blob= --get --get-all --get-regexp --get-urlmatch --replace-all --add --unset --unset-all --rename-section --remove-section --list --fixed-value --edit --get-color --get-colorbool --type= --bool --int --bool-or-int --bool-or-str --path --expiry-date --null --name-only --includes --show-origin --show-scope --default= --no-global -- --no-system --no-local --no-worktree --no-file --no-blob --no-get --no-get-all --no-get-regexp --no-get-urlmatch --no-replace-all --no-add --no-unset --no-unset-all --no-rename-section --no-remove-section --no-list --no-fixed-value --no-edit --no-get-color --no-get-colorbool --no-type --no-null --no-name-only --no-includes --no-show-origin --no-show-scope --no-default" -__gitcomp_builtin_count_objects_default=" --verbose --human-readable --no-verbose -- --no-human-readable" -__gitcomp_builtin_credential_cache_default=" --timeout= --socket= --no-timeout -- --no-socket" -__gitcomp_builtin_credential_cache__daemon_default=" --debug --no-debug" -__gitcomp_builtin_credential_store_default=" --file= --no-file" -__gitcomp_builtin_describe_default=" --contains --debug --all --tags --long --first-parent --abbrev --exact-match --candidates= --match= --exclude= --always --dirty --broken --no-contains -- --no-debug --no-all --no-tags --no-long --no-first-parent --no-abbrev --no-exact-match --no-candidates --no-match --no-exclude --no-always --no-dirty --no-broken" -__gitcomp_builtin_difftool_default=" --gui --dir-diff --no-prompt --symlinks --tool= --tool-help --trust-exit-code --extcmd= --no-index --index -- --no-gui --no-dir-diff --no-symlinks --no-tool --no-tool-help --no-trust-exit-code --no-extcmd" -__gitcomp_builtin_env__helper_default=" --type= --default= --exit-code --no-default -- --no-exit-code" -__gitcomp_builtin_fast_export_default=" --progress= --signed-tags= --tag-of-filtered-object= --reencode= --export-marks= --import-marks= --import-marks-if-exists= --fake-missing-tagger --full-tree --use-done-feature --no-data --refspec= --anonymize --anonymize-map= --reference-excluded-parents --show-original-ids --mark-tags --data -- --no-progress --no-signed-tags --no-tag-of-filtered-object --no-reencode --no-export-marks --no-import-marks --no-import-marks-if-exists --no-fake-missing-tagger --no-full-tree --no-use-done-feature --no-refspec --no-anonymize --no-reference-excluded-parents --no-show-original-ids --no-mark-tags" -__gitcomp_builtin_fetch_default=" --verbose --quiet --all --set-upstream --append --atomic --upload-pack= --force --multiple --tags --jobs= --prefetch --prune --prune-tags --recurse-submodules --dry-run --write-fetch-head --keep --update-head-ok --progress --depth= --shallow-since= --shallow-exclude= --deepen= --unshallow --refetch --update-shallow --refmap= --server-option= --ipv4 --ipv6 --negotiation-tip= --negotiate-only --filter= --auto-maintenance --auto-gc --show-forced-updates --write-commit-graph --stdin --no-verbose -- --no-quiet --no-all --no-set-upstream --no-append --no-atomic --no-upload-pack --no-force --no-multiple --no-tags --no-jobs --no-prefetch --no-prune --no-prune-tags --no-recurse-submodules --no-dry-run --no-write-fetch-head --no-keep --no-update-head-ok --no-progress --no-depth --no-shallow-since --no-shallow-exclude --no-deepen --no-update-shallow --no-server-option --no-ipv4 --no-ipv6 --no-negotiation-tip --no-negotiate-only --no-filter --no-auto-maintenance --no-auto-gc --no-show-forced-updates --no-write-commit-graph --no-stdin" -__gitcomp_builtin_fmt_merge_msg_default=" --log --message= --into-name= --file= --no-log -- --no-message --no-into-name --no-file" -__gitcomp_builtin_for_each_ref_default=" --shell --perl --python --tcl --count= --format= --color --sort= --points-at= --merged --no-merged --contains --no-contains --ignore-case -- --no-shell --no-perl --no-python --no-tcl --no-count --no-format --no-color --no-sort --no-points-at --no-ignore-case" -__gitcomp_builtin_for_each_repo_default=" --config= --no-config" -__gitcomp_builtin_format_patch_default=" --numbered --no-numbered --signoff --stdout --cover-letter --numbered-files --suffix= --start-number= --reroll-count= --filename-max-length= --rfc --cover-from-description= --subject-prefix= --output-directory= --keep-subject --no-binary --zero-commit --ignore-if-in-upstream --no-stat --add-header= --to= --cc= --from --in-reply-to= --attach --inline --thread --signature= --base= --signature-file= --quiet --progress --interdiff= --range-diff= --creation-factor= --binary -- --no-numbered --no-signoff --no-stdout --no-cover-letter --no-numbered-files --no-suffix --no-start-number --no-reroll-count --no-filename-max-length --no-cover-from-description --no-zero-commit --no-ignore-if-in-upstream --no-add-header --no-to --no-cc --no-from --no-in-reply-to --no-attach --no-thread --no-signature --no-base --no-signature-file --no-quiet --no-progress --no-interdiff --no-range-diff --no-creation-factor" -__gitcomp_builtin_fsck_default=" --verbose --unreachable --dangling --tags --root --cache --reflogs --full --connectivity-only --strict --lost-found --progress --name-objects --no-verbose -- --no-unreachable --no-dangling --no-tags --no-root --no-cache --no-reflogs --no-full --no-connectivity-only --no-strict --no-lost-found --no-progress --no-name-objects" -__gitcomp_builtin_fsck_objects_default=" --verbose --unreachable --dangling --tags --root --cache --reflogs --full --connectivity-only --strict --lost-found --progress --name-objects --no-verbose -- --no-unreachable --no-dangling --no-tags --no-root --no-cache --no-reflogs --no-full --no-connectivity-only --no-strict --no-lost-found --no-progress --no-name-objects" -__gitcomp_builtin_fsmonitor__daemon_default="" -__gitcomp_builtin_gc_default=" --quiet --prune --aggressive --keep-largest-pack --no-quiet -- --no-prune --no-aggressive --no-keep-largest-pack" -__gitcomp_builtin_grep_default=" --cached --no-index --untracked --exclude-standard --recurse-submodules --invert-match --ignore-case --word-regexp --text --textconv --recursive --max-depth= --extended-regexp --basic-regexp --fixed-strings --perl-regexp --line-number --column --full-name --files-with-matches --name-only --files-without-match --only-matching --count --color --break --heading --context= --before-context= --after-context= --threads= --show-function --function-context --and --or --not --quiet --all-match --index -- --no-cached --no-untracked --no-exclude-standard --no-recurse-submodules --no-invert-match --no-ignore-case --no-word-regexp --no-text --no-textconv --no-recursive --no-extended-regexp --no-basic-regexp --no-fixed-strings --no-perl-regexp --no-line-number --no-column --no-full-name --no-files-with-matches --no-name-only --no-files-without-match --no-only-matching --no-count --no-color --no-break --no-heading --no-context --no-before-context --no-after-context --no-threads --no-show-function --no-function-context --no-or --no-quiet --no-all-match" -__gitcomp_builtin_hash_object_default=" --stdin --stdin-paths --no-filters --literally --path= --filters -- --no-stdin --no-stdin-paths --no-literally --no-path" -__gitcomp_builtin_help_default=" --all --external-commands --aliases --man --web --info --verbose --guides --config --no-external-commands -- --no-aliases --no-man --no-web --no-info --no-verbose" -__gitcomp_builtin_hook_default="" -__gitcomp_builtin_init_default=" --template= --bare --shared --quiet --separate-git-dir= --initial-branch= --object-format= --no-template -- --no-bare --no-quiet --no-separate-git-dir --no-initial-branch --no-object-format" -__gitcomp_builtin_init_db_default=" --template= --bare --shared --quiet --separate-git-dir= --initial-branch= --object-format= --no-template -- --no-bare --no-quiet --no-separate-git-dir --no-initial-branch --no-object-format" -__gitcomp_builtin_interpret_trailers_default=" --in-place --trim-empty --where= --if-exists= --if-missing= --only-trailers --only-input --unfold --parse --no-divider --trailer= --divider -- --no-in-place --no-trim-empty --no-where --no-if-exists --no-if-missing --no-only-trailers --no-only-input --no-unfold --no-trailer" -__gitcomp_builtin_log_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate" -__gitcomp_builtin_ls_files_default=" --cached --deleted --modified --others --ignored --stage --killed --directory --eol --empty-directory --unmerged --resolve-undo --exclude= --exclude-from= --exclude-per-directory= --exclude-standard --full-name --recurse-submodules --error-unmatch --with-tree= --abbrev --debug --deduplicate --sparse --no-cached -- --no-deleted --no-modified --no-others --no-ignored --no-stage --no-killed --no-directory --no-eol --no-empty-directory --no-unmerged --no-resolve-undo --no-exclude-per-directory --no-recurse-submodules --no-error-unmatch --no-with-tree --no-abbrev --no-debug --no-deduplicate --no-sparse" -__gitcomp_builtin_ls_remote_default=" --quiet --upload-pack= --tags --heads --refs --get-url --sort= --symref --server-option= --no-quiet -- --no-upload-pack --no-tags --no-heads --no-refs --no-get-url --no-sort --no-symref --no-server-option" -__gitcomp_builtin_ls_tree_default=" --long --name-only --name-status --object-only --full-name --full-tree --format= --abbrev --no-full-name -- --no-full-tree --no-abbrev" -__gitcomp_builtin_merge_default=" --stat --summary --log --squash --commit --edit --cleanup= --ff --ff-only --rerere-autoupdate --verify-signatures --strategy= --strategy-option= --message= --file --into-name= --verbose --quiet --abort --quit --continue --allow-unrelated-histories --progress --gpg-sign --autostash --overwrite-ignore --signoff --no-verify --verify -- --no-stat --no-summary --no-log --no-squash --no-commit --no-edit --no-cleanup --no-ff --no-rerere-autoupdate --no-verify-signatures --no-strategy --no-strategy-option --no-message --no-into-name --no-verbose --no-quiet --no-abort --no-quit --no-continue --no-allow-unrelated-histories --no-progress --no-gpg-sign --no-autostash --no-overwrite-ignore --no-signoff" -__gitcomp_builtin_merge_base_default=" --all --octopus --independent --is-ancestor --fork-point --no-all" -__gitcomp_builtin_merge_file_default=" --stdout --diff3 --zdiff3 --ours --theirs --union --marker-size= --quiet --no-stdout -- --no-diff3 --no-zdiff3 --no-ours --no-theirs --no-union --no-marker-size --no-quiet" -__gitcomp_builtin_mktree_default=" --missing --batch --no-missing -- --no-batch" -__gitcomp_builtin_multi_pack_index_default=" --object-dir= --no-object-dir" -__gitcomp_builtin_mv_default=" --verbose --dry-run --sparse --no-verbose -- --no-dry-run --no-sparse" -__gitcomp_builtin_name_rev_default=" --name-only --tags --refs= --exclude= --all --stdin --annotate-stdin --undefined --always --no-name-only -- --no-tags --no-refs --no-exclude --no-all --no-stdin --no-annotate-stdin --no-undefined --no-always" -__gitcomp_builtin_notes_default=" --ref= --no-ref" -__gitcomp_builtin_pack_objects_default=" --quiet --progress --all-progress --all-progress-implied --index-version= --max-pack-size= --local --incremental --window= --window-memory= --depth= --reuse-delta --reuse-object --delta-base-offset --threads= --non-empty --revs --unpacked --all --reflog --indexed-objects --stdin-packs --stdout --include-tag --keep-unreachable --pack-loose-unreachable --unpack-unreachable --sparse --thin --shallow --honor-pack-keep --keep-pack= --compression= --keep-true-parents --use-bitmap-index --write-bitmap-index --filter= --missing= --exclude-promisor-objects --delta-islands --uri-protocol= --no-quiet -- --no-progress --no-all-progress --no-all-progress-implied --no-local --no-incremental --no-window --no-depth --no-reuse-delta --no-reuse-object --no-delta-base-offset --no-threads --no-non-empty --no-revs --no-stdin-packs --no-stdout --no-include-tag --no-keep-unreachable --no-pack-loose-unreachable --no-unpack-unreachable --no-sparse --no-thin --no-shallow --no-honor-pack-keep --no-keep-pack --no-compression --no-keep-true-parents --no-use-bitmap-index --no-write-bitmap-index --no-filter --no-exclude-promisor-objects --no-delta-islands --no-uri-protocol" -__gitcomp_builtin_pack_refs_default=" --all --prune --no-all -- --no-prune" -__gitcomp_builtin_pickaxe_default=" --incremental --root --show-stats --progress --score-debug --show-name --show-number --porcelain --line-porcelain --show-email --ignore-rev= --ignore-revs-file= --color-lines --color-by-age --minimal --contents= --abbrev --no-incremental -- --no-root --no-show-stats --no-progress --no-score-debug --no-show-name --no-show-number --no-porcelain --no-line-porcelain --no-show-email --no-ignore-rev --no-ignore-revs-file --no-color-lines --no-color-by-age --no-minimal --no-contents --no-abbrev" -__gitcomp_builtin_prune_default=" --dry-run --verbose --progress --expire= --exclude-promisor-objects --no-dry-run -- --no-verbose --no-progress --no-expire --no-exclude-promisor-objects" -__gitcomp_builtin_prune_packed_default=" --dry-run --quiet --no-dry-run -- --no-quiet" -__gitcomp_builtin_pull_default=" --verbose --quiet --progress --recurse-submodules --rebase --stat --log --signoff --squash --commit --edit --cleanup= --ff --ff-only --verify --verify-signatures --autostash --strategy= --strategy-option= --gpg-sign --allow-unrelated-histories --all --append --upload-pack= --force --tags --prune --jobs --dry-run --keep --depth= --shallow-since= --shallow-exclude= --deepen= --unshallow --update-shallow --refmap= --server-option= --ipv4 --ipv6 --negotiation-tip= --show-forced-updates --set-upstream --no-verbose -- --no-quiet --no-progress --no-recurse-submodules --no-rebase --no-stat --no-log --no-signoff --no-squash --no-commit --no-edit --no-cleanup --no-ff --no-verify --no-verify-signatures --no-autostash --no-strategy --no-strategy-option --no-gpg-sign --no-allow-unrelated-histories --no-all --no-append --no-upload-pack --no-force --no-tags --no-prune --no-jobs --no-dry-run --no-keep --no-depth --no-shallow-since --no-shallow-exclude --no-deepen --no-update-shallow --no-server-option --no-ipv4 --no-ipv6 --no-negotiation-tip --no-show-forced-updates --no-set-upstream" -__gitcomp_builtin_push_default=" --verbose --quiet --repo= --all --mirror --delete --tags --dry-run --porcelain --force --force-with-lease --force-if-includes --recurse-submodules= --receive-pack= --exec= --set-upstream --progress --prune --no-verify --follow-tags --signed --atomic --push-option= --ipv4 --ipv6 --verify -- --no-verbose --no-quiet --no-repo --no-all --no-mirror --no-delete --no-tags --no-dry-run --no-porcelain --no-force --no-force-with-lease --no-force-if-includes --no-recurse-submodules --no-receive-pack --no-exec --no-set-upstream --no-progress --no-prune --no-follow-tags --no-signed --no-atomic --no-push-option --no-ipv4 --no-ipv6" -__gitcomp_builtin_range_diff_default=" --creation-factor= --no-dual-color --notes --left-only --right-only --patch --no-patch --unified --function-context --raw --patch-with-raw --patch-with-stat --numstat --shortstat --dirstat --cumulative --dirstat-by-file --check --summary --name-only --name-status --stat --stat-width= --stat-name-width= --stat-graph-width= --stat-count= --compact-summary --binary --full-index --color --ws-error-highlight= --abbrev --src-prefix= --dst-prefix= --line-prefix= --no-prefix --inter-hunk-context= --output-indicator-new= --output-indicator-old= --output-indicator-context= --break-rewrites --find-renames --irreversible-delete --find-copies --find-copies-harder --no-renames --rename-empty --follow --minimal --ignore-all-space --ignore-space-change --ignore-space-at-eol --ignore-cr-at-eol --ignore-blank-lines --ignore-matching-lines= --indent-heuristic --patience --histogram --diff-algorithm= --anchored= --word-diff --word-diff-regex= --color-words --color-moved --color-moved-ws= --relative --text --exit-code --quiet --ext-diff --textconv --ignore-submodules --submodule --ita-invisible-in-index --ita-visible-in-index --pickaxe-all --pickaxe-regex --rotate-to= --skip-to= --find-object= --diff-filter= --output= --dual-color -- --no-creation-factor --no-notes --no-left-only --no-right-only --no-function-context --no-compact-summary --no-full-index --no-color --no-abbrev --no-find-copies-harder --no-rename-empty --no-follow --no-minimal --no-ignore-matching-lines --no-indent-heuristic --no-color-moved --no-color-moved-ws --no-relative --no-text --no-exit-code --no-quiet --no-ext-diff --no-textconv" -__gitcomp_builtin_read_tree_default=" --index-output= --empty --verbose --trivial --aggressive --reset --prefix= --exclude-per-directory= --dry-run --no-sparse-checkout --debug-unpack --recurse-submodules --quiet --sparse-checkout -- --no-empty --no-verbose --no-trivial --no-aggressive --no-reset --no-dry-run --no-debug-unpack --no-recurse-submodules --no-quiet" -__gitcomp_builtin_rebase_default=" --onto= --keep-base --no-verify --quiet --verbose --no-stat --signoff --committer-date-is-author-date --reset-author-date --ignore-whitespace --whitespace= --force-rebase --no-ff --continue --skip --abort --quit --edit-todo --show-current-patch --apply --merge --interactive --rerere-autoupdate --empty= --autosquash --gpg-sign --autostash --exec= --rebase-merges --fork-point --strategy= --strategy-option= --root --reschedule-failed-exec --reapply-cherry-picks --verify --stat --ff -- --no-onto --no-keep-base --no-quiet --no-verbose --no-signoff --no-committer-date-is-author-date --no-reset-author-date --no-ignore-whitespace --no-whitespace --no-force-rebase --no-rerere-autoupdate --no-autosquash --no-gpg-sign --no-autostash --no-exec --no-rebase-merges --no-fork-point --no-strategy --no-strategy-option --no-root --no-reschedule-failed-exec --no-reapply-cherry-picks" -__gitcomp_builtin_receive_pack_default=" --quiet --no-quiet" -__gitcomp_builtin_reflog_default="" -__gitcomp_builtin_remote_default=" --verbose --no-verbose" -__gitcomp_builtin_repack_default=" --quiet --local --write-bitmap-index --delta-islands --unpack-unreachable= --keep-unreachable --window= --window-memory= --depth= --threads= --max-pack-size= --pack-kept-objects --keep-pack= --geometric= --write-midx --no-quiet -- --no-local --no-write-bitmap-index --no-delta-islands --no-unpack-unreachable --no-keep-unreachable --no-window --no-window-memory --no-depth --no-threads --no-max-pack-size --no-pack-kept-objects --no-keep-pack --no-geometric --no-write-midx" -__gitcomp_builtin_replace_default=" --list --delete --edit --graft --convert-graft-file --raw --format= --no-raw -- --no-format" -__gitcomp_builtin_rerere_default=" --rerere-autoupdate --no-rerere-autoupdate" -__gitcomp_builtin_reset_default=" --quiet --no-refresh --mixed --soft --hard --merge --keep --recurse-submodules --patch --intent-to-add --pathspec-from-file= --pathspec-file-nul --refresh -- --no-quiet --no-mixed --no-soft --no-hard --no-merge --no-keep --no-recurse-submodules --no-patch --no-intent-to-add --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_restore_default=" --source= --staged --worktree --ignore-unmerged --overlay --quiet --recurse-submodules --progress --merge --conflict= --ours --theirs --patch --ignore-skip-worktree-bits --pathspec-from-file= --pathspec-file-nul --no-source -- --no-staged --no-worktree --no-ignore-unmerged --no-overlay --no-quiet --no-recurse-submodules --no-progress --no-merge --no-conflict --no-patch --no-ignore-skip-worktree-bits --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_revert_default=" --quit --continue --abort --skip --cleanup= --no-commit --edit --signoff --mainline= --rerere-autoupdate --strategy= --strategy-option= --gpg-sign --commit -- --no-cleanup --no-edit --no-signoff --no-mainline --no-rerere-autoupdate --no-strategy --no-strategy-option --no-gpg-sign" -__gitcomp_builtin_rm_default=" --dry-run --quiet --cached --ignore-unmatch --sparse --pathspec-from-file= --pathspec-file-nul --no-dry-run -- --no-quiet --no-cached --no-ignore-unmatch --no-sparse --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_send_pack_default=" --verbose --quiet --receive-pack= --exec= --remote= --all --dry-run --mirror --force --signed --push-option= --progress --thin --atomic --stateless-rpc --stdin --helper-status --force-with-lease --force-if-includes --no-verbose -- --no-quiet --no-receive-pack --no-exec --no-remote --no-all --no-dry-run --no-mirror --no-force --no-signed --no-push-option --no-progress --no-thin --no-atomic --no-stateless-rpc --no-stdin --no-helper-status --no-force-with-lease --no-force-if-includes" -__gitcomp_builtin_shortlog_default=" --committer --numbered --summary --email --group= --no-committer -- --no-numbered --no-summary --no-email --no-group" -__gitcomp_builtin_show_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate" -__gitcomp_builtin_show_branch_default=" --all --remotes --color --more --list --no-name --current --sha1-name --merge-base --independent --topo-order --topics --sparse --date-order --reflog --name -- --no-all --no-remotes --no-color --no-more --no-list --no-current --no-sha1-name --no-merge-base --no-independent --no-topo-order --no-topics --no-sparse --no-date-order" -__gitcomp_builtin_show_index_default=" --object-format= --no-object-format" -__gitcomp_builtin_show_ref_default=" --tags --heads --verify --head --dereference --hash --abbrev --quiet --exclude-existing --no-tags -- --no-heads --no-verify --no-head --no-dereference --no-hash --no-abbrev --no-quiet" -__gitcomp_builtin_sparse_checkout_default="" -__gitcomp_builtin_stage_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-removal --refresh --ignore-errors --ignore-missing --sparse --chmod= --pathspec-from-file= --pathspec-file-nul --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit --no-force --no-update --no-renormalize --no-intent-to-add --no-all --no-ignore-removal --no-refresh --no-ignore-errors --no-ignore-missing --no-sparse --no-chmod --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_stash_default="" -__gitcomp_builtin_status_default=" --verbose --short --branch --show-stash --ahead-behind --porcelain --long --null --untracked-files --ignored --ignore-submodules --column --no-renames --find-renames --renames -- --no-verbose --no-short --no-branch --no-show-stash --no-ahead-behind --no-porcelain --no-long --no-null --no-untracked-files --no-ignored --no-ignore-submodules --no-column" -__gitcomp_builtin_stripspace_default=" --strip-comments --comment-lines" -__gitcomp_builtin_switch_default=" --create= --force-create= --guess --discard-changes --quiet --recurse-submodules --progress --merge --conflict= --detach --track --orphan= --ignore-other-worktrees --no-create -- --no-force-create --no-guess --no-discard-changes --no-quiet --no-recurse-submodules --no-progress --no-merge --no-conflict --no-detach --no-track --no-orphan --no-ignore-other-worktrees" -__gitcomp_builtin_symbolic_ref_default=" --quiet --delete --short --no-quiet -- --no-delete --no-short" -__gitcomp_builtin_tag_default=" --list --delete --verify --annotate --message= --file= --edit --sign --cleanup= --local-user= --force --create-reflog --column --contains --no-contains --merged --no-merged --sort= --points-at --format= --color --ignore-case -- --no-annotate --no-file --no-edit --no-sign --no-cleanup --no-local-user --no-force --no-create-reflog --no-column --no-sort --no-points-at --no-format --no-color --no-ignore-case" -__gitcomp_builtin_update_index_default=" --ignore-submodules --add --replace --remove --unmerged --refresh --really-refresh --cacheinfo --chmod= --assume-unchanged --no-assume-unchanged --skip-worktree --no-skip-worktree --ignore-skip-worktree-entries --info-only --force-remove --stdin --index-info --unresolve --again --ignore-missing --verbose --clear-resolve-undo --index-version= --split-index --untracked-cache --test-untracked-cache --force-untracked-cache --force-write-index --fsmonitor --fsmonitor-valid --no-fsmonitor-valid -- --no-ignore-submodules --no-add --no-replace --no-remove --no-unmerged --no-ignore-skip-worktree-entries --no-info-only --no-force-remove --no-ignore-missing --no-verbose --no-index-version --no-split-index --no-untracked-cache --no-test-untracked-cache --no-force-untracked-cache --no-force-write-index --no-fsmonitor" -__gitcomp_builtin_update_ref_default=" --no-deref --stdin --create-reflog --deref -- --no-stdin --no-create-reflog" -__gitcomp_builtin_update_server_info_default=" --force --no-force" -__gitcomp_builtin_upload_pack_default=" --stateless-rpc --strict --timeout= --no-stateless-rpc -- --no-strict --no-timeout" -__gitcomp_builtin_verify_commit_default=" --verbose --raw --no-verbose -- --no-raw" -__gitcomp_builtin_verify_pack_default=" --verbose --stat-only --object-format= --no-verbose -- --no-stat-only --no-object-format" -__gitcomp_builtin_verify_tag_default=" --verbose --raw --format= --no-verbose -- --no-raw --no-format" -__gitcomp_builtin_version_default=" --build-options --no-build-options" -__gitcomp_builtin_whatchanged_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate" -__gitcomp_builtin_write_tree_default=" --missing-ok --prefix= --no-missing-ok -- --no-prefix" -__gitcomp_builtin_send_email_default="--sender= --from= --smtp-auth= --8bit-encoding= --no-format-patch --no-bcc --no-suppress-from --no-annotate --relogin-delay= --no-cc --no-signed-off-cc --no-signed-off-by-cc --no-chain-reply-to --smtp-debug= --smtp-domain= --chain-reply-to --dry-run --compose --bcc= --smtp-user= --thread --cc-cover --identity= --to= --reply-to= --no-cc-cover --suppress-cc= --to-cmd= --smtp-server= --smtp-ssl-cert-path= --no-thread --smtp-server-option= --quiet --batch-size= --envelope-sender= --smtp-ssl --no-to --validate --format-patch --suppress-from --cc= --compose-encoding= --to-cover --in-reply-to= --annotate --smtp-encryption= --cc-cmd= --smtp-server-port= --smtp-pass= --signed-off-cc --signed-off-by-cc --no-xmailer --subject= --no-to-cover --confirm= --transfer-encoding= --no-smtp-auth --sendmail-cmd= --no-validate --no-identity --dump-aliases --xmailer --force --numbered --no-numbered --signoff --stdout --cover-letter --numbered-files --suffix= --start-number= --reroll-count= --filename-max-length= --rfc --cover-from-description= --subject-prefix= --output-directory= --keep-subject --no-binary --zero-commit --ignore-if-in-upstream --no-stat --add-header= --from --attach --inline --signature= --base= --signature-file= --progress --interdiff= --range-diff= --creation-factor= --binary -- --no-signoff --no-stdout --no-cover-letter --no-numbered-files --no-suffix --no-start-number --no-reroll-count --no-filename-max-length --no-cover-from-description --no-zero-commit --no-ignore-if-in-upstream --no-add-header --no-from --no-in-reply-to --no-attach --no-signature --no-base --no-signature-file --no-quiet --no-progress --no-interdiff --no-range-diff --no-creation-factor" - -__gitcomp_builtin_get_default () -{ - eval "test -n \"\$${1}_default\" && echo \"\$${1}_default\"" -} - # This function is equivalent to # # __gitcomp_opts "$(git xxx --git-completion-helper) ..." @@ -457,11 +353,9 @@ __gitcomp_builtin () else completion_helper="--git-completion-helper" fi - completion="$(__git ${cmd/_/ } $completion_helper || - __gitcomp_builtin_get_default $var)" || return # leading and trailing spaces are significant to make # option removal work correctly. - options=" $incl $completion " + options=" $incl $(__git ${cmd/_/ } $completion_helper) " || return for i in $excl; do options="${options/ $i / }" @@ -604,6 +498,7 @@ __git_heads () local pfx="${1-}" cur_="${2-}" sfx="${3-}" __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/heads/$cur_*" "refs/heads/$cur_*/**" } @@ -617,6 +512,7 @@ __git_remote_heads () local pfx="${1-}" cur_="${2-}" sfx="${3-}" __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/remotes/$cur_*" "refs/remotes/$cur_*/**" } @@ -627,6 +523,7 @@ __git_tags () local pfx="${1-}" cur_="${2-}" sfx="${3-}" __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/tags/$cur_*" "refs/tags/$cur_*/**" } @@ -646,6 +543,7 @@ __git_dwim_remote_heads () # but only output if the branch name is unique __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ --sort="refname:strip=3" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \ uniq -u } @@ -670,6 +568,7 @@ __git_refs () local format refs local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}" local match="${4-}" + local umatch="${4-}" local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers __git_find_repo_path @@ -693,12 +592,19 @@ __git_refs () fi fi + if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1" + then + # uppercase with tr instead of ${match,^^} for bash 3.2 compatibility + umatch=$(echo "$match" | tr a-z A-Z 2>/dev/null || echo "$match") + fi + if [ "$list_refs_from" = path ]; then if [[ "$cur_" == ^* ]]; then pfx="$pfx^" fer_pfx="$fer_pfx^" cur_=${cur_#^} match=${match#^} + umatch=${umatch#^} fi case "$cur_" in refs|refs/*) @@ -709,7 +615,7 @@ __git_refs () *) for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do case "$i" in - $match*) + $match*|$umatch*) if [ -e "$dir/$i" ]; then echo "$pfx$i$sfx" fi @@ -723,6 +629,7 @@ __git_refs () ;; esac __git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "${refs[@]}" if [ -n "$track" ]; then __git_dwim_remote_heads "$pfx" "$match" "$sfx" @@ -742,15 +649,16 @@ __git_refs () *) if [ "$list_refs_from" = remote ]; then case "HEAD" in - $match*) echo "${pfx}HEAD$sfx" ;; + $match*|$umatch*) echo "${pfx}HEAD$sfx" ;; esac __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/remotes/$remote/$match*" \ "refs/remotes/$remote/$match*/**" else local query_symref case "HEAD" in - $match*) query_symref="HEAD" ;; + $match*|$umatch*) query_symref="HEAD" ;; esac __git ls-remote "$remote" $query_symref \ "refs/tags/$match*" "refs/heads/$match*" \ @@ -888,7 +796,6 @@ __git_list_merge_strategies () }' } -__git_merge_strategies_default='octopus ours recursive resolve subtree' __git_merge_strategies= # 'git merge -s help' (and thus detection of the merge strategy # list) fails, unfortunately, if run outside of any git working @@ -898,8 +805,7 @@ __git_merge_strategies= __git_compute_merge_strategies () { test -n "$__git_merge_strategies" || - { __git_merge_strategies=$(__git_list_merge_strategies); - __git_merge_strategies="${__git_merge_strategies:-__git_merge_strategies_default}"; } + __git_merge_strategies=$(__git_list_merge_strategies) } __git_merge_strategy_options="ours theirs subtree subtree= patience @@ -2281,7 +2187,7 @@ _git_reflog () fi } -__git_send_email_options="--no-cc-cover --cc= --no-bcc --force --relogin-delay= --to= --suppress-cc= --no-annotate --no-chain-reply-to --sendmail-cmd= --no-identity --transfer-encoding= --validate --no-smtp-auth --confirm= --no-format-patch --reply-to= --smtp-pass= --smtp-server= --annotate --envelope-sender= --no-validate --dry-run --no-thread --smtp-debug= --no-to --thread --no-xmailer --identity= --no-signed-off-cc --no-signed-off-by-cc --smtp-domain= --to-cover --8bit-encoding= --bcc= --smtp-ssl-cert-path= --smtp-user= --cc-cmd= --to-cmd= --no-cc --smtp-server-option= --in-reply-to= --subject= --batch-size= --smtp-auth= --compose --smtp-server-port= --xmailer --no-to-cover --chain-reply-to --smtp-encryption= --dump-aliases --quiet --smtp-ssl --signed-off-cc --signed-off-by-cc --suppress-from --compose-encoding= --no-suppress-from --sender= --from= --format-patch --cc-cover --numbered --no-numbered --signoff --stdout --cover-letter --numbered-files --suffix= --start-number= --reroll-count= --filename-max-length= --rfc --cover-from-description= --subject-prefix= --output-directory= --keep-subject --no-binary --zero-commit --ignore-if-in-upstream --no-stat --add-header= --from --attach --inline --signature= --base= --signature-file= --progress --interdiff= --range-diff= --creation-factor= --binary -- --no-signoff --no-stdout --no-cover-letter --no-numbered-files --no-suffix --no-start-number --no-reroll-count --no-filename-max-length --no-cover-from-description --no-zero-commit --no-ignore-if-in-upstream --no-add-header --no-from --no-in-reply-to --no-attach --no-signature --no-base --no-signature-file --no-quiet --no-progress --no-interdiff --no-range-diff --no-creation-factor" +__gitcomp_builtin_send_email_default="--8bit-encoding= --add-header= --annotate --attach --base= --batch-size= --bcc= --binary --cc-cmd= --cc-cover --cc= --chain-reply-to --compose --compose-encoding= --confirm= --cover-from-description= --cover-letter --creation-factor= --dry-run --dump-aliases --envelope-sender= --filename-max-length= --force --force-in-body-from --format-patch --from --from= --identity= --ignore-if-in-upstream --in-reply-to= --inline --interdiff= --keep-subject --numbered --numbered-files --output-directory= --progress --quiet --range-diff= --relogin-delay= --reply-to= --reroll-count= --rfc --sender= --sendmail-cmd= --signature-file= --signature= --signed-off-by-cc --signed-off-cc --signoff --smtp-auth= --smtp-debug= --smtp-domain= --smtp-encryption= --smtp-pass= --smtp-server-option= --smtp-server-port= --smtp-server= --smtp-ssl --smtp-ssl-cert-path= --smtp-user= --start-number= --stdout --subject-prefix= --subject= --suffix= --suppress-cc= --suppress-from --thread --to-cmd= --to-cover --to= --transfer-encoding= --v= --validate --xmailer --zero-commit -- --no-add-header --no-annotate --no-attach --no-base --no-bcc --no-binary --no-cc --no-cc-cover --no-chain-reply-to --no-cover-from-description --no-cover-letter --no-creation-factor --no-filename-max-length --no-force-in-body-from --no-format-patch --no-from --no-identity --no-ignore-if-in-upstream --no-in-reply-to --no-interdiff --no-numbered --no-numbered-files --no-progress --no-quiet --no-range-diff --no-reroll-count --no-signature --no-signature-file --no-signed-off-by-cc --no-signed-off-cc --no-signoff --no-smtp-auth --no-start-number --no-stat --no-stdout --no-suffix --no-suppress-from --no-thread --no-to --no-to-cover --no-validate --no-xmailer --no-zero-commit" __git_send_email_confirm_options="always never auto cc compose" __git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all" @@ -2321,7 +2227,11 @@ _git_send_email () return ;; --*) - __gitcomp_builtin send-email "$__git_send_email_options $__git_format_patch_extra_options" + # Older versions of git send-email don't have all the options + git send-email --git-completion-helper | grep -q annotate || + __gitcomp_builtin_send_email=$__gitcomp_builtin_send_email_default + + __gitcomp_builtin send-email "$__git_format_patch_extra_options" return ;; esac @@ -2456,7 +2366,25 @@ __git_config_vars= __git_compute_config_vars () { test -n "$__git_config_vars" || - __git_config_vars="$(git help --config-for-completion | sort -u)" + __git_config_vars="$(git help --config-for-completion)" +} + +__git_compute_config_sections_old () +{ + __git_compute_config_vars + echo "$__git_config_vars" | + awk -F . '{ dict[$1] = 1 } END { for (e in dict) print e }' +} + +__git_config_sections= +__git_compute_config_sections () +{ + test -n "$__git_config_sections" || + __git_config_sections="$( + git help --config-sections-for-completion > /dev/null 2>&1 && + git help --config-sections-for-completion || + __git_compute_config_sections_old + )" } # Completes possible values of various configuration variables. @@ -2670,16 +2598,8 @@ __git_complete_config_variable_name () __gitcomp "$__git_config_vars" "" "$cur_" "$sfx" ;; *) - __git_compute_config_vars - __gitcomp_nl "$(echo "$__git_config_vars" | - awk -F . '{ - sections[$1] = 1 - } - END { - for (s in sections) - print s "." - } - ')" "" "$cur_" "" + __git_compute_config_sections + __gitcomp_nl "$__git_config_sections" "" "$cur_" "." ;; esac } @@ -3628,43 +3548,6 @@ __git_complete () ___git_complete $1 $func } -if ! git --list-cmds=main >/dev/null 2>&1; then - - declare -A __git_cmds - __git_cmds[list-complete]="apply blame cherry config difftool fsck help instaweb mergetool prune reflog remote repack replace request-pull send-email show-branch stage whatchanged" - __git_cmds[list-guide]="attributes cli core-tutorial credentials cvs-migration diffcore everyday faq glossary hooks ignore mailmap modules namespaces remote-helpers repository-layout revisions submodules tutorial tutorial-2 workflows" - __git_cmds[list-mainporcelain]="add am archive bisect branch bundle checkout cherry-pick citool clean clone commit describe diff fetch format-patch gc grep gui init log maintenance merge mv notes pull push range-diff rebase reset restore revert rm shortlog show sparse-checkout stash status submodule switch tag worktree gitk" - __git_cmds[main]="add add--interactive am annotate apply archimport archive bisect bisect--helper blame branch bugreport bundle cat-file check-attr check-ignore check-mailmap check-ref-format checkout checkout--worker checkout-index cherry cherry-pick citool clean clone column commit commit-graph commit-tree config count-objects credential credential-cache credential-cache--daemon credential-store cvsexportcommit cvsimport cvsserver daemon describe diff diff-files diff-index diff-tree difftool difftool--helper env--helper fast-export fast-import fetch fetch-pack filter-branch fmt-merge-msg for-each-ref for-each-repo format-patch fsck fsck-objects fsmonitor--daemon gc get-tar-commit-id grep gui gui--askpass hash-object help hook http-backend http-fetch http-push imap-send index-pack init init-db instaweb interpret-trailers legacy-rebase legacy-stash log ls-files ls-remote ls-tree mailinfo mailsplit maintenance merge merge-base merge-file merge-index merge-octopus merge-one-file merge-ours merge-recursive merge-recursive-ours merge-recursive-theirs merge-resolve merge-subtree merge-tree mergetool mktag mktree multi-pack-index mv name-rev notes p4 pack-objects pack-redundant pack-refs patch-id pickaxe prune prune-packed pull push quiltimport range-diff read-tree rebase rebase--helper receive-pack reflog relink remote remote-ext remote-fd remote-ftp remote-ftps remote-http remote-https remote-testsvn repack replace request-pull rerere reset restore rev-list rev-parse revert rm send-email send-pack serve sh-i18n--envsubst shell shortlog show show-branch show-index show-ref sparse-checkout stage stash status stripspace submodule submodule--helper svn switch symbolic-ref tag unpack-file unpack-objects update-index update-ref update-server-info upload-archive upload-archive--writer upload-pack var verify-commit verify-pack verify-tag version web--browse whatchanged worktree write-tree" - __git_cmds[others]="" - __git_cmds[parseopt]="add am apply archive bisect--helper blame branch bugreport cat-file check-attr check-ignore check-mailmap checkout checkout--worker checkout-index cherry cherry-pick clean clone column commit commit-graph config count-objects credential-cache credential-cache--daemon credential-store describe difftool env--helper fast-export fetch fmt-merge-msg for-each-ref for-each-repo format-patch fsck fsck-objects fsmonitor--daemon gc grep hash-object help hook init init-db interpret-trailers log ls-files ls-remote ls-tree merge merge-base merge-file mktree multi-pack-index mv name-rev notes pack-objects pack-refs pickaxe prune prune-packed pull push range-diff read-tree rebase receive-pack reflog remote repack replace rerere reset restore revert rm send-pack shortlog show show-branch show-index show-ref sparse-checkout stage stash status stripspace switch symbolic-ref tag update-index update-ref update-server-info upload-pack verify-commit verify-pack verify-tag version whatchanged write-tree " - - # Override __git - __git () - { - case "$1" in - --list-cmds=*) - while read -r -d ',' x; do - case "$x" in - nohelpers) - ;; - alias) - ;; - config) - ;; - *) - echo ${__git_cmds[$x]} - ;; - esac - done <<< "${1##--list-cmds=}," - return - ;; - esac - git ${__git_C_args:+"${__git_C_args[@]}"} \ - ${__git_dir:+--git-dir="$__git_dir"} "$@" 2>/dev/null - } - -fi - ___git_complete git __git_main ___git_complete gitk __gitk_main diff --git a/plugins/gitfast/git-prompt.sh b/plugins/gitfast/git-prompt.sh index 1435548e0..76ee4ab1e 100644 --- a/plugins/gitfast/git-prompt.sh +++ b/plugins/gitfast/git-prompt.sh @@ -84,6 +84,10 @@ # single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted # by setting GIT_PS1_OMITSPARSESTATE. # +# If you would like to see a notification on the prompt when there are +# unresolved conflicts, set GIT_PS1_SHOWCONFLICTSTATE to "yes". The +# prompt will include "|CONFLICT". +# # If you would like to see more information about the identity of # commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE # to one of these values: @@ -96,9 +100,7 @@ # # If you would like a colored hint about the current dirty state, set # GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on -# the colored output of "git status -sb" and are available only when -# using __git_ps1 for PROMPT_COMMAND or precmd in Bash, -# but always available in Zsh. +# the colored output of "git status -sb". # # If you would like __git_ps1 to do nothing in the case when the current # directory is set up to be ignored by git, then set @@ -255,12 +257,12 @@ __git_ps1_colorize_gitstring () local c_lblue='%F{blue}' local c_clear='%f' else - # Using \[ and \] around colors is necessary to prevent + # Using \001 and \002 around colors is necessary to prevent # issues with command line editing/browsing/completion! - local c_red='\[\e[31m\]' - local c_green='\[\e[32m\]' - local c_lblue='\[\e[1;34m\]' - local c_clear='\[\e[0m\]' + local c_red=$'\001\e[31m\002' + local c_green=$'\001\e[32m\002' + local c_lblue=$'\001\e[1;34m\002' + local c_clear=$'\001\e[0m\002' fi local bad_color=$c_red local ok_color=$c_green @@ -508,6 +510,12 @@ __git_ps1 () r="$r $step/$total" fi + local conflict="" # state indicator for unresolved conflicts + if [[ "${GIT_PS1_SHOWCONFLICTSTATE}" == "yes" ]] && + [[ $(git ls-files --unmerged 2>/dev/null) ]]; then + conflict="|CONFLICT" + fi + local w="" local i="" local s="" @@ -564,15 +572,12 @@ __git_ps1 () b="\${__git_ps1_branch_name}" fi - # NO color option unless in PROMPT_COMMAND mode or it's Zsh if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then - if [ $pcmode = yes ] || [ -n "${ZSH_VERSION-}" ]; then - __git_ps1_colorize_gitstring - fi + __git_ps1_colorize_gitstring fi local f="$h$w$i$s$u$p" - local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}" + local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}${conflict}" if [ $pcmode = yes ]; then if [ "${__git_printf_supports_v-}" != yes ]; then diff --git a/plugins/gitignore/README.md b/plugins/gitignore/README.md index 753dd31fd..23c7887cf 100644 --- a/plugins/gitignore/README.md +++ b/plugins/gitignore/README.md @@ -1,6 +1,6 @@ # gitignore -This plugin enables you the use of [gitignore.io](https://www.gitignore.io/) from the command line. You need an active internet connection. +This plugin enables you the use of [gitignore.io](https://www.toptal.com/developers/gitignore) from the command line. You need an active internet connection. To use it, add `gitignore` to the plugins array in your zshrc file: diff --git a/plugins/gitignore/gitignore.plugin.zsh b/plugins/gitignore/gitignore.plugin.zsh index a687f5cce..3271d61a9 100644 --- a/plugins/gitignore/gitignore.plugin.zsh +++ b/plugins/gitignore/gitignore.plugin.zsh @@ -1,7 +1,7 @@ -function gi() { curl -fLw '\n' https://www.gitignore.io/api/"${(j:,:)@}" } +function gi() { curl -fLw '\n' https://www.toptal.com/developers/gitignore/api/"${(j:,:)@}" } _gitignoreio_get_command_list() { - curl -sfL https://www.gitignore.io/api/list | tr "," "\n" + curl -sfL https://www.toptal.com/developers/gitignore/api/list | tr "," "\n" } _gitignoreio () { diff --git a/plugins/gnu-utils/gnu-utils.plugin.zsh b/plugins/gnu-utils/gnu-utils.plugin.zsh index 9419127d8..6023bf2b4 100644 --- a/plugins/gnu-utils/gnu-utils.plugin.zsh +++ b/plugins/gnu-utils/gnu-utils.plugin.zsh @@ -19,7 +19,7 @@ __gnu_utils() { 'gchown' 'gchroot' 'gcksum' 'gcomm' 'gcp' 'gcsplit' 'gcut' 'gdate' 'gdd' 'gdf' 'gdir' 'gdircolors' 'gdirname' 'gdu' 'gecho' 'genv' 'gexpand' 'gexpr' 'gfactor' 'gfalse' 'gfmt' 'gfold' 'ggroups' 'ghead' 'ghostid' - 'gid' 'ginstall' 'gjoin' 'gkill' 'glink' 'gln' 'glogname' 'gls' 'gmd5sum' + 'gid' 'gindent' 'ginstall' 'gjoin' 'gkill' 'glink' 'gln' 'glogname' 'gls' 'gmd5sum' 'gmkdir' 'gmkfifo' 'gmknod' 'gmktemp' 'gmv' 'gnice' 'gnl' 'gnohup' 'gnproc' 'god' 'gpaste' 'gpathchk' 'gpinky' 'gpr' 'gprintenv' 'gprintf' 'gptx' 'gpwd' 'greadlink' 'grm' 'grmdir' 'gruncon' 'gseq' 'gsha1sum' 'gsha224sum' @@ -61,3 +61,14 @@ __gnu_utils_preexec() { autoload -Uz add-zsh-hook add-zsh-hook preexec __gnu_utils_preexec + +# lib/theme-and-appearance.zsh sets the alias for ls not knowing that +# we'll be using GNU ls. We'll reset this to use GNU ls --color. +# See https://github.com/ohmyzsh/ohmyzsh/issues/11503 +# +# The ls alias might look like: +# - ls='ls -G' +# - ls='gls --color=tty' +if [[ -x "${commands[gls]}" && "${aliases[ls]}" = (*-G*|gls*) ]]; then + alias ls='ls --color=tty' +fi diff --git a/plugins/golang/README.md b/plugins/golang/README.md index 3b7d1e19f..128cc7fbb 100644 --- a/plugins/golang/README.md +++ b/plugins/golang/README.md @@ -16,11 +16,12 @@ plugins=(... golang) | gob | `go build` | Build your code | | goc | `go clean` | Removes object files from package source directories | | god | `go doc` | Prints documentation comments | +| goe | `go env` | Prints Go environment information | | gof | `go fmt` | Gofmt formats (aligns and indents) Go programs. | | gofa | `go fmt ./...` | Run go fmt for all packages in current directory, recursively | | gofx | `go fix` | Update packages to use a new API | | gog | `go get` | Downloads packages and then installs them to $GOPATH | -| gog | `go get ./...` | Installs all dependencies in current directory, recursively | +| goga | `go get ./...` | Installs all dependencies in current directory, recursively | | goi | `go install` | Compiles and installs packages to $GOPATH | | gol | `go list` | Lists Go packages | | gom | `go mod` | Access to operations on modules | @@ -35,4 +36,5 @@ plugins=(... golang) | gotod | `go tool dist` | Utility to bootstrap, build and test go runtime | | gotofx | `go tool fix` | Fixes an application to use newer features | | gov | `go vet` | Vet examines Go source code and reports suspicious constructs | +| gove | `go version` | Prints Go version | | gow | `go work` | Work provides access to operations on workspaces | diff --git a/plugins/golang/golang.plugin.zsh b/plugins/golang/golang.plugin.zsh index 0dbaab069..45ccd3a1c 100644 --- a/plugins/golang/golang.plugin.zsh +++ b/plugins/golang/golang.plugin.zsh @@ -13,6 +13,7 @@ unset p alias gob='go build' alias goc='go clean' alias god='go doc' +alias goe='go env' alias gof='go fmt' alias gofa='go fmt ./...' alias gofx='go fix' @@ -32,4 +33,5 @@ alias gotoc='go tool compile' alias gotod='go tool dist' alias gotofx='go tool fix' alias gov='go vet' +alias gove='go version' alias gow='go work' diff --git a/plugins/gradle/_gradle b/plugins/gradle/_gradle index e77b23cdb..f8df928b4 100644 --- a/plugins/gradle/_gradle +++ b/plugins/gradle/_gradle @@ -1,4 +1,6 @@ #compdef gradle gradlew gw +# THE LINE ABOVE MUST BE THE FIRST LINE OF THIS FILE IN ORDER FOR COMPLETION TO WORK + # # Taken from https://github.com/gradle/gradle-completion # Copyright (c) 2017 Eric Wendelin @@ -116,9 +118,9 @@ __gradle-generate-tasks-cache() { # Reuse Gradle Daemon if IDLE but don't start a new one. local gradle_tasks_output if [[ ! -z "$($gradle_cmd --status 2>/dev/null | grep IDLE)" ]]; then - gradle_tasks_output="$($gradle_cmd --daemon --build-file $gradle_build_file --console plain -q tasks --all 2>/dev/null)" + gradle_tasks_output="$($gradle_cmd --daemon --no-scan --build-file $gradle_build_file --console=plain -q tasks --all 2>/dev/null)" else - gradle_tasks_output="$($gradle_cmd --no-daemon --build-file $gradle_build_file --console plain -q tasks --all 2>/dev/null)" + gradle_tasks_output="$($gradle_cmd --no-daemon --no-scan --build-file $gradle_build_file --console=plain -q tasks --all 2>/dev/null)" fi local gradle_all_tasks="" root_tasks="" subproject_tasks="" output_line local -a match @@ -180,7 +182,7 @@ __gradle_tasks() { local cached_checksum="$(cat $cache_dir/$cache_name.md5)" local -a cached_tasks if [[ -z $cur ]]; then - cached_tasks=(${(f)"$(cat $cache_dir/$cached_checksum)"}) + cached_tasks=(${(f)"$(grep -v "^\\\:" $cache_dir/$cached_checksum)"}) else cached_tasks=(${(f)"$(grep "^${cur//:/\\\\:}" $cache_dir/$cached_checksum)"}) fi @@ -191,7 +193,7 @@ __gradle_tasks() { # Regenerate tasks cache in the background if [[ $gradle_files_checksum != "$(cat $cache_dir/$cache_name.md5)" || ! -f $cache_dir/$gradle_files_checksum || $(wc -c < $cache_dir/$gradle_files_checksum) -le 1 ]]; then - $(__gradle-generate-tasks-cache 1>&2 2>/dev/null &) + $(__gradle-generate-tasks-cache &> /dev/null &) fi else _describe 'built-in tasks' '( @@ -262,7 +264,10 @@ __gradle_subcommand() { {-b,--build-file}'[Specifies the build file.]:build script:_files -g \*.gradle' \ {-C,--cache}'[Specifies how compiled build scripts should be cached.]:cache policy:(on rebuild)' \ {-c,--settings-file}'[Specifies the settings file.]:settings file:_files -g \*.gradle' \ + '(--configuration-cache)--no-configuration-cache[Disables the configuration cache. Gradle will not reuse the build configuration from previous builds.]' \ + '--configuration-cache-problems=[Configures how the configuration cache handles problems]:problem handling:(fail warn)' \ '(--no-configure-on-demand)--configure-on-demand[Only relevant projects are configured in this build run.]' \ + '(--no-configuration-cache)--configuration-cache[Enables the configuration cache. Gradle will try to reuse the build configuration from previous builds.]' \ '--console=[Specifies which type of console output to generate.]:console output type:(plain auto rich verbose)' \ '--continue[Continues task execution after a task failure.]' \ '-Dorg.gradle.cache.reserved.mb=[Reserve Gradle Daemon memory for operations.]' \ @@ -276,6 +281,7 @@ __gradle_subcommand() { '-Dorg.gradle.logging.level=[Set default Gradle log level.]:log level:(quiet warn lifecycle info debug)' \ '-Dorg.gradle.parallel=[Set true to enable parallel project builds.]:enable parallel build:(true false)' \ '-Dorg.gradle.priority=[Set priority for Gradle worker processes.]:priority:(low normal)' \ + '-Dorg.gradle.unsafe.watch-fs=[Set true to enable Gradle file watcher.]:enable watcher:(true false)' \ '-Dorg.gradle.warning.mode=[Set types of warnings to log.]:warning level:(all summary none)' \ '-Dorg.gradle.workers.max=[Set the number of workers Gradle is allowed to use.]' \ '(-i --info -w --warn -q --quiet)'{-d,--debug}'[Log in debug mode (includes normal stacktrace).]' \ @@ -314,6 +320,7 @@ __gradle_subcommand() { '(--write-locks)--update-locks[Perform a partial update of the dependency lock.]' \ '(-d --debug -q --quiet -i --info)'{-w,--warn}'[Log warnings and errors only.]' \ '--warning-mode=[Set types of warnings to log.]:warning mode:(all summary none)' \ + '(--no-watch-fs)--watch-fs[Gradle watches filesystem for incremental builds.]' \ '(--update-locks)--write-locks[Persists dependency resolution for locked configurations.]' \ {-x,--exclude-task}'[Specify a task to be excluded from execution.]' && ret=0 ;; @@ -347,6 +354,9 @@ _gradle() { {-b,--build-file}'[Specifies the build file.]:build script:_files -g \*.gradle' \ {-C,--cache}'[Specifies how compiled build scripts should be cached.]:cache policy:(on rebuild)' \ {-c,--settings-file}'[Specifies the settings file.]:settings file:_files -g \*.gradle:->argument-expected' \ + '(--no-configuration-cache)--configuration-cache[Enables the configuration cache. Gradle will try to reuse the build configuration from previous builds.]' \ + '(--configuration-cache)--no-configuration-cache[Disables the configuration cache. Gradle will not reuse the build configuration from previous builds.]' \ + '--configuration-cache-problems=[Configures how the configuration cache handles problems]:problem handling:(fail warn)' \ '(--no-configure-on-demand)--configure-on-demand[Only relevant projects are configured in this build run.]' \ '--console=[Specifies which type of console output to generate.]:console output type:(plain auto rich verbose)' \ '--continue[Continues task execution after a task failure.]' \ @@ -361,6 +371,7 @@ _gradle() { '-Dorg.gradle.logging.level=[Set default Gradle log level.]:log level:(quiet warn lifecycle info debug)' \ '-Dorg.gradle.parallel=[Set true to enable parallel project builds.]:(true false)' \ '-Dorg.gradle.priority=[Set priority for Gradle worker processes.]:priority:(low normal)' \ + '-Dorg.gradle.unsafe.watch-fs=[Set true to enable Gradle file watcher.]:enable watcher:(true false)' \ '-Dorg.gradle.warning.mode=[Set types of warnings to log.]:warning level:(all summary none)' \ '-Dorg.gradle.workers.max=[Set the number of workers Gradle is allowed to use.]' \ '(-i --info -w --warn -q --quiet)'{-d,--debug}'[Log in debug mode (includes normal stacktrace).]' \ @@ -404,6 +415,7 @@ _gradle() { '(-d --debug -q --quiet -i --info)'{-w,--warn}'[Log warnings and errors only.]' \ '--warning-mode=[Set types of warnings to log.]:warning mode:(all summary none)' \ '(--update-locks)--write-locks[Persists dependency resolution for locked configurations.]' \ + '(--no-watch-fs)--watch-fs[Gradle watches filesystem for incremental builds.]' \ {-x,--exclude-task}'[Specify a task to be excluded from execution.]' \ '(-)*:: :->task-or-option' && ret=0 diff --git a/plugins/gradle/gradle.plugin.zsh b/plugins/gradle/gradle.plugin.zsh index 5bca364d1..dacc46478 100644 --- a/plugins/gradle/gradle.plugin.zsh +++ b/plugins/gradle/gradle.plugin.zsh @@ -6,7 +6,7 @@ function gradle-or-gradlew() { # taken from https://github.com/gradle/gradle-completion local dir="$PWD" project_root="$PWD" while [[ "$dir" != / ]]; do - if [[ -f "$dir/settings.gradle" || -f "$dir/settings.gradle.kts" || -f "$dir/gradlew" ]]; then + if [[ -x "$dir/gradlew" ]]; then project_root="$dir" break fi diff --git a/plugins/grc/grc.plugin.zsh b/plugins/grc/grc.plugin.zsh index b709b9e02..55ffc1a1e 100644 --- a/plugins/grc/grc.plugin.zsh +++ b/plugins/grc/grc.plugin.zsh @@ -2,8 +2,10 @@ # common grc.zsh paths files=( - /etc/grc.zsh # default - /usr/local/etc/grc.zsh # homebrew + /etc/grc.zsh # default + /usr/local/etc/grc.zsh # homebrew darwin-x64 + /opt/homebrew/etc/grc.zsh # homebrew darwin-arm64 + /usr/share/grc/grc.zsh # Gentoo Linux (app-misc/grc) ) # verify the file is readable and source it diff --git a/plugins/hasura/README.md b/plugins/hasura/README.md new file mode 100644 index 000000000..d7db9ed92 --- /dev/null +++ b/plugins/hasura/README.md @@ -0,0 +1,9 @@ +# Hasura plugin + +This plugin adds completion for [the Hasura CLI](https://hasura.io/docs/latest/hasura-cli/index/). + +To use it, add `hasura` to the plugins array in your zshrc file: + +```zsh +plugins=(... hasura) +``` diff --git a/plugins/hasura/hasura.plugin.zsh b/plugins/hasura/hasura.plugin.zsh new file mode 100644 index 000000000..18254c43b --- /dev/null +++ b/plugins/hasura/hasura.plugin.zsh @@ -0,0 +1,13 @@ +if (( ! $+commands[hasura] )); then + return +fi + +# If the completion file does not exist, generate it and then source it +# Otherwise, source it and regenerate in the background +if [[ ! -f "$ZSH_CACHE_DIR/completions/_hasura" ]]; then + hasura completion zsh --file "$ZSH_CACHE_DIR/completions/_hasura" >/dev/null + source "$ZSH_CACHE_DIR/completions/_hasura" +else + source "$ZSH_CACHE_DIR/completions/_hasura" + hasura completion zsh --file "$ZSH_CACHE_DIR/completions/_hasura" >/dev/null &| +fi diff --git a/plugins/helm/README.md b/plugins/helm/README.md index 49844c78f..8be024bfb 100644 --- a/plugins/helm/README.md +++ b/plugins/helm/README.md @@ -1,9 +1,18 @@ # Helm plugin -This plugin adds completion for [Helm](https://helm.sh/), the Kubernetes package manager. +This plugin adds completion and aliases for [Helm](https://helm.sh/), the Kubernetes package manager. To use it, add `helm` to the plugins array in your zshrc file: ```zsh plugins=(... helm) ``` + +## Aliases + +| Alias | Full command | +| ----- | ------------ | +| h | helm | +| hin | helm install | +| hse | helm search | +| hup | helm upgrade | diff --git a/plugins/helm/helm.plugin.zsh b/plugins/helm/helm.plugin.zsh index 151c43d88..7fc05be98 100644 --- a/plugins/helm/helm.plugin.zsh +++ b/plugins/helm/helm.plugin.zsh @@ -11,3 +11,8 @@ else source "$ZSH_CACHE_DIR/completions/_helm" helm completion zsh | tee "$ZSH_CACHE_DIR/completions/_helm" >/dev/null &| fi + +alias h='helm' +alias hin='helm install' +alias hse='helm search' +alias hup='helm upgrade' diff --git a/plugins/heroku-alias/README.md b/plugins/heroku-alias/README.md new file mode 100644 index 000000000..4b7b953fd --- /dev/null +++ b/plugins/heroku-alias/README.md @@ -0,0 +1,127 @@ +# heroku-alias +🧬 Full alias for heroku cli + +|🚀 last maj|📡 source| +|---|---| +|02/06/2020|[heroku cli doc](https://devcenter.heroku.com/articles/heroku-cli-commands)| + +# Alias list + +## general +| Alias | Command | +| ------------- | ------------- | +| h | heroku | +| hauto | heroku autocomplete $(echo $SHELL) | +| hl | heroku local | + +## config +| Alias | Command | +| ------------- | ------------- | +| hc | heroku config | +| hca | heroku config -a | +| hcr | heroku config -r | +| hcs | heroku config:set | +| hcu | heroku config:unset | +| hcfile | function hcfile bellow | + +```sh +hcfile() { + echo " Which platform [-r/a name] ? " + read platform + echo " Which file ? " + read file + while read line; + do heroku config:set "$platform" "$line"; + done < "$file" +} +``` + +## apps and favorites +| Alias | Command | +| ------------- | ------------- | +| ha | heroku apps | +| hpop | heroku create | +| hkill | heroku apps:destroy | +| hlog | heroku apps:errors | +| hfav | heroku apps:favorites | +| hfava | heroku apps:favorites:add | +| hfavr | heroku apps:favorites:remove | +| hai | heroku apps:info | +| hair | heroku apps:info -r | +| haia | heroku apps:info -a | + +# auth +| Alias | Command | +| ------------- | ------------- | +| h2fa | heroku auth:2fa | +| h2far | heroku auth:2fa:disable | + +# access +| Alias | Command | +| ------------- | ------------- | +| hac | heroku access | +| hacr | heroku access -r | +| haca | heroku access -a | +| hadd | heroku access:add | +| hdel | heroku access:remove | +| hup | heroku access:update | + +## addons +| Alias | Command | +| ------------- | ------------- | +| hads | heroku addons -A | +| hada | heroku addons -a | +| hadr | heroku addons -r | +| hadat | heroku addons:attach | +| hadc | heroku addons:create | +| hadel | heroku addons:destroy | +| hadde | heroku addons:detach | +| hadoc | heroku addons:docs | + +## login +| Alias | Command | +| ------------- | ------------- | +| hin | heroku login | +| hout | heroku logout | +| hi | heroku login -i | +| hwho | heroku auth:whoami | + +## authorizations +| Alias | Command | +| ------------- | ------------- | +| hth | heroku authorizations | +| hthadd | heroku authorizations:create | +| hthif | heroku authorizations:info | +| hthdel | heroku authorizations:revoke | +| hthrot | heroku authorizations:rotate | +| hthup | heroku authorizations:update | + +## plugins +| Alias | Command | +| ------------- | ------------- | +| hp | heroku plugins | + +# log +| Alias | Command | +| ------------- | ------------- | +|hg | heroku logs| +| hgt | heroku log tail | + +# database +| Alias | Command | +| ------------- | ------------- | +| hpg | heroku pg | +| hpsql | heroku pg:psql | +| hpb | heroku pg:backups | +| hpbc | heroku pg:backups:capture | +| hpbd | heroku pg:backups:download | +| hpbr | heroku pg:backups:restore | + +# certs +| Alias | Command | +| ------------- | ------------- | +| hssl | heroku certs | +| hssli | heroku certs:info | +| hssla | heroku certs:add | +| hsslu | heroku certs:update | +| hsslr | heroku certs:remove | diff --git a/plugins/heroku-alias/heroku.alias.sh b/plugins/heroku-alias/heroku.alias.sh new file mode 100644 index 000000000..7daf715b5 --- /dev/null +++ b/plugins/heroku-alias/heroku.alias.sh @@ -0,0 +1,92 @@ +# general +alias h='heroku' +alias hauto='heroku autocomplete $(echo $SHELL)' +alias hl='heroku local' + +# log +alias hg='heroku logs' +alias hgt='heroku log tail' + +# database +alias hpg='heroku pg' +alias hpsql='heroku pg:psql' +alias hpb='heroku pg:backups' +alias hpbc='heroku pg:backups:capture' +alias hpbd='heroku pg:backups:download' +alias hpbr='heroku pg:backups:restore' + +# config +alias hc='heroku config' +alias hca='heroku config -a' +alias hcr='heroku config -r' +alias hcs='heroku config:set' +alias hcu='heroku config:unset' + +# this function allow to load multi env set in a file +hcfile() { + echo 'Which platform [-r/a name] ?' + read platform + echo 'Which file ?' + read file + while read line; + do heroku config:set "$platform" "$line"; + done < "$file" +} + +# apps and favorites +alias ha='heroku apps' +alias hpop='heroku create' +alias hkill='heroku apps:destroy' +alias hlog='heroku apps:errors' +alias hfav='heroku apps:favorites' +alias hfava='heroku apps:favorites:add' +alias hfavr='heroku apps:favorites:remove' +alias hai='heroku apps:info' +alias hair='heroku apps:info -r' +alias haia='heroku apps:info -a' + +# auth +alias h2fa='heroku auth:2fa' +alias h2far='heroku auth:2fa:disable' + +# access +alias hac='heroku access' +alias hacr='heroku access -r' +alias haca='heroku access -a' +alias hadd='heroku access:add' +alias hdel='heroku access:remove' +alias hup='heroku access:update' + +# addons +alias hads='heroku addons -A' +alias hada='heroku addons -a' +alias hadr='heroku addons -r' +alias hadat='heroku addons:attach' +alias hadc='heroku addons:create' +alias hadel='heroku addons:destroy' +alias hadde='heroku addons:detach' +alias hadoc='heroku addons:docs' + +# login +alias hin='heroku login' +alias hout='heroku logout' +alias hi='heroku login -i' +alias hwho='heroku auth:whoami' + +# authorizations +alias hth='heroku authorizations' +alias hthadd='heroku authorizations:create' +alias hthif='heroku authorizations:info' +alias hthdel='heroku authorizations:revoke' +alias hthrot='heroku authorizations:rotate' +alias hthup='heroku authorizations:update' + +# plugins +alias hp='heroku plugins' + +# cert +alias hssl='heroku certs' +alias hssli='heroku certs:info' +alias hssla='heroku certs:add' +alias hsslu='heroku certs:update' +alias hsslr='heroku certs:remove' diff --git a/plugins/history/README.md b/plugins/history/README.md index a9d480f46..73d6a5052 100644 --- a/plugins/history/README.md +++ b/plugins/history/README.md @@ -13,5 +13,6 @@ plugins=(... history) | Alias | Command | Description | |-------|----------------------|------------------------------------------------------------------| | `h` | `history` | Prints your command history | +| `hl` | `history \| less` | Pipe history output to less to search and navigate it easily | | `hs` | `history \| grep` | Use grep to search your command history | | `hsi` | `history \| grep -i` | Use grep to do a case-insensitive search of your command history | diff --git a/plugins/history/history.plugin.zsh b/plugins/history/history.plugin.zsh index 9cee48fe4..fb3e31389 100644 --- a/plugins/history/history.plugin.zsh +++ b/plugins/history/history.plugin.zsh @@ -1,3 +1,4 @@ alias h='history' +alias hl='history | less' alias hs='history | grep' alias hsi='history | grep -i' diff --git a/plugins/hitchhiker/fortunes/hitchhiker b/plugins/hitchhiker/fortunes/hitchhiker index 825b86cd6..94cc1c835 100644 --- a/plugins/hitchhiker/fortunes/hitchhiker +++ b/plugins/hitchhiker/fortunes/hitchhiker @@ -80,7 +80,7 @@ % "The fronting for the eighty-yard-long marble-topped bar had been made by stitching together nearly twenty thousand Antarean Mosaic Lizard skins, despite the fact that the twenty thousand lizards concerned had needed them to keep their insides in." -- The Book decribing Milliways' politically incorrect decor. +- The Book describing Milliways' politically incorrect decor. % "`...and the Universe,' continued the waiter, determined not to be deflected on his home stretch, `will explode later for your pleasure.' Ford's head swivelled slowly towards him. He spoke with feeling. `Wow,' he said, `What sort of drinks do you serve in this place?' The waiter laughed a polite little waiter's laugh. `Ah,' he said, `I think sir has perhaps misunderstood me.' `Oh, I hope not,' breathed Ford." @@ -104,7 +104,7 @@ % "`The first ten million years were the worst,' said Marvin, `and the second ten million, they were the worst too. The third ten million I didn't enjoy at all. After that I went into a bit of a decline.'" -- Marvin reflecting back on his 576,000,003,579 year career as Milliways' car park attendent. +- Marvin reflecting back on his 576,000,003,579 year career as Milliways' car park attendant. % "`Incidentally,' he said, `what does teleport mean?' Another moment passed. Slowly, the others turned to face him. `Probably the wrong moment to ask,' said Arthur, `It's just I remember you use the word a short while ago and I only bring it up because...' `Where,' said Ford quietly, `does it say teleport?' `Well, just over here in fact,' said Arthur, pointing at a dark control box in the rear of the cabin, `Just under the word "emergency", above the word "system" and beside the sign saying "out of order".'" @@ -122,7 +122,7 @@ - Ford "debating" what to do with fire with a marketing girl. % -"The story goes that I first had the idea for THHGTTG while lying drunk in a field in Innsbruck (or `Spain' as the BBC TV publicity department authoritatively has it, probably because it's easier to spell)." - Foreward by DNA. +"The story goes that I first had the idea for THHGTTG while lying drunk in a field in Innsbruck (or `Spain' as the BBC TV publicity department authoritatively has it, probably because it's easier to spell)." - Foreword by DNA. FORD Six pints of bitter. And quickly please, the world's about to end. BARMAN Oh yes, sir? Nice weather for it. % @@ -162,7 +162,7 @@ ARTHUR It probably seems a terrible thing to say, but you know what I sometimes - Arthur discovering a way of coping with life on Prehistoric Earth. % -"`... then I decided that I was a lemon for a couple of weeks. I kept myself amused all that time jumping in and out of a gin and tonic.' Arthur cleared his throat, and then did it again. `Where,' he said, `did you...?' `Find a gin and tonic?' said Ford brightly. `I found a small lake that thought it was a gin and tonic, and jumped in and out of that. At least, I think it thought it was a gin and tonic.' `I may,' he addded with a grin which would have sent sane men scampering into the trees, `have been imagining it.'" +"`... then I decided that I was a lemon for a couple of weeks. I kept myself amused all that time jumping in and out of a gin and tonic.' Arthur cleared his throat, and then did it again. `Where,' he said, `did you...?' `Find a gin and tonic?' said Ford brightly. `I found a small lake that thought it was a gin and tonic, and jumped in and out of that. At least, I think it thought it was a gin and tonic.' `I may,' he added with a grin which would have sent sane men scampering into the trees, `have been imagining it.'" - Ford updating Arthur about what he's been doing for the past four years. % @@ -194,31 +194,31 @@ ARTHUR It probably seems a terrible thing to say, but you know what I sometimes - One of the more preferable pieces of advice contained in the Guide. % -"His eyes seemed to be popping out of his head. He wasn't certain if this was because they were trying to see more clearly, or if they simply wanted to leave at this point."QUOTEHERESTRINGMAGIC1234- Arthur trying to see who had diverted him from going to a party. +"His eyes seemed to be popping out of his head. He wasn't certain if this was because they were trying to see more clearly, or if they simply wanted to leave at this point." - Arthur trying to see who had diverted him from going to a party. % -"Arthur yawed wildly as his skin tried to jump one way and his skeleton the other, whilst his brain tried to work out which of his ears it most wanted to crawl out of. `Bet you weren't expecting to see me again,' said the monster, which Arthur couldn't help thinking was a strange remark for it to make, seeing as he had never met the creature before. He could tell that he hadn't met the creature before from the simple fact that he was able to sleep at nights."QUOTEHERESTRINGMAGIC1234- Arthur discovering who had diverted him from going to a party. +"Arthur yawed wildly as his skin tried to jump one way and his skeleton the other, whilst his brain tried to work out which of his ears it most wanted to crawl out of. `Bet you weren't expecting to see me again,' said the monster, which Arthur couldn't help thinking was a strange remark for it to make, seeing as he had never met the creature before. He could tell that he hadn't met the creature before from the simple fact that he was able to sleep at nights." - Arthur discovering who had diverted him from going to a party. % -"`That young girl is one of the least benightedly unintelligent organic life forms it has been my profound lack of pleasure not to be able to avoid meeting.'"QUOTEHERESTRINGMAGIC1234- Marvin's first ever compliment about anybody. +"`That young girl is one of the least benightedly unintelligent organic life forms it has been my profound lack of pleasure not to be able to avoid meeting.'" - Marvin's first ever compliment about anybody. % -"Arthur hoped and prayed that there wasn't an afterlife. Then he realised there was a contradiction there and merely hoped that there wasn't an afterlife."QUOTEHERESTRINGMAGIC1234- Arthur realising that he's in a certain death situation with a supernova bomb that is shaped like a cricket ball. +"Arthur hoped and prayed that there wasn't an afterlife. Then he realised there was a contradiction there and merely hoped that there wasn't an afterlife." - Arthur realising that he's in a certain death situation with a supernova bomb that is shaped like a cricket ball. % -"`Credit?' he said. `Aaaargggh...' These two words are usually coupled together in the Old Pink Dog Bar."QUOTEHERESTRINGMAGIC1234- Ford in a spot of bother. +"`Credit?' he said. `Aaaargggh...' These two words are usually coupled together in the Old Pink Dog Bar." - Ford in a spot of bother. % -"`...we might as well start with where your hand is now.' Arthur said, `So which way do I go?' `Down,' said Fenchurch, `on this occasion.' He moved his hand. `Down,' she said, `is in fact the other way.' `Oh yes.'"QUOTEHERESTRINGMAGIC1234- Arthur trying to discover which part of Fenchurch is wrong. +"`...we might as well start with where your hand is now.' Arthur said, `So which way do I go?' `Down,' said Fenchurch, `on this occasion.' He moved his hand. `Down,' she said, `is in fact the other way.' `Oh yes.'" - Arthur trying to discover which part of Fenchurch is wrong. % -"There was a point to this story, but it has temporarily escaped the chronicler's mind."QUOTEHERESTRINGMAGIC1234- This line perhaps best sums up the whole book. +"There was a point to this story, but it has temporarily escaped the chronicler's mind." - This line perhaps best sums up the whole book. % -"The last time anybody made a list of the top hundred character attributes of New Yorkers, common sense snuck in at number 79. .... When it's fall in New York, the air smells as if someone's been frying goats in it, and if you are keen to breathe the best plan is to open a window and stick your head in a building."QUOTEHERESTRINGMAGIC1234- Nuff said?? +"The last time anybody made a list of the top hundred character attributes of New Yorkers, common sense snuck in at number 79. .... When it's fall in New York, the air smells as if someone's been frying goats in it, and if you are keen to breathe the best plan is to open a window and stick your head in a building." - Nuff said?? % -"`What's been happening here?' he demanded. `Oh just the nicest things, sir, just the nicest things. can I sit on your lap please?'" "`Colin, I am going to abandon you to your fate.' `I'm so happy.'" "`It will be very, very nasty for you, and that's just too bad. Got it?' `I gurgle with pleasure.'"QUOTEHERESTRINGMAGIC1234- Ford and Colin the robot. +"`What's been happening here?' he demanded. `Oh just the nicest things, sir, just the nicest things. can I sit on your lap please?'" "`Colin, I am going to abandon you to your fate.' `I'm so happy.'" "`It will be very, very nasty for you, and that's just too bad. Got it?' `I gurgle with pleasure.'" - Ford and Colin the robot. % -"What the hell, he thought, you're only young once, and threw himself out of the window. That would at least keep the element of surprise on his side."QUOTEHERESTRINGMAGIC1234- Ford outwitting a Vogon with a rocket launcher by going into another certain death situation. +"What the hell, he thought, you're only young once, and threw himself out of the window. That would at least keep the element of surprise on his side." - Ford outwitting a Vogon with a rocket launcher by going into another certain death situation. % -"The major difference between a thing that might go wrong and a thing that cannot possibly go wrong is that when a thing that cannot possibly go wrong goes wrong it usually turns out to be impossible to get at or repair."QUOTEHERESTRINGMAGIC1234- One of the laws of computers and programming revealed. +"The major difference between a thing that might go wrong and a thing that cannot possibly go wrong is that when a thing that cannot possibly go wrong goes wrong it usually turns out to be impossible to get at or repair." - One of the laws of computers and programming revealed. % -"`You know they've reintroduced the death penalty for insurance company directors?' `Really?' said Arthur. `No I didn't. For what offence?' Trillian frowned. `What do you mean, offence?' `I see.'"QUOTEHERESTRINGMAGIC1234- Evidence that there will be some justice in the Universe eventually. +"`You know they've reintroduced the death penalty for insurance company directors?' `Really?' said Arthur. `No I didn't. For what offence?' Trillian frowned. `What do you mean, offence?' `I see.'" - Evidence that there will be some justice in the Universe eventually. % -"`She hit me on the head with the rock again.' `I think I can confirm that that was my daughter.' `Sweet kid.' `You have to get to know her,' said Arthur. `She eases up does she?' `No,' said Arthur, `but you get a better sense of when to duck.'"QUOTEHERESTRINGMAGIC1234- Ford and Arthur on Random. +"`She hit me on the head with the rock again.' `I think I can confirm that that was my daughter.' `Sweet kid.' `You have to get to know her,' said Arthur. `She eases up does she?' `No,' said Arthur, `but you get a better sense of when to duck.'" - Ford and Arthur on Random. % "Far out in the uncharted backwaters of the unfashionable end of the western spiral arm of the Galaxy lies a small unregarded yellow sun. " % diff --git a/plugins/httpie/_httpie b/plugins/httpie/_httpie index 4d702ef60..11bc8e1f8 100644 --- a/plugins/httpie/_httpie +++ b/plugins/httpie/_httpie @@ -1,6 +1,6 @@ #compdef http # ------------------------------------------------------------------------------ -# Copyright (c) 2015 Github zsh-users - http://github.com/zsh-users +# Copyright (c) 2015 GitHub zsh-users - http://github.com/zsh-users # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/plugins/iterm2/README.md b/plugins/iterm2/README.md index 50cdebf5e..3d11622df 100644 --- a/plugins/iterm2/README.md +++ b/plugins/iterm2/README.md @@ -2,11 +2,20 @@ This plugin adds a few functions that are useful when using [iTerm2](https://www.iterm2.com/). + To use it, add _iterm2_ to the plugins array of your zshrc file: ``` plugins=(... iterm2) ``` +Optionally, the plugin also applies the [Shell Integration Script for iTerm2](https://iterm2.com/documentation-shell-integration.html). +You can enable the integration with zstyle. It's important to add this line +before the line sourcing oh-my-zsh: + +``` +zstyle :omz:plugins:iterm2 shell-integration yes +``` + ## Plugin commands * `_iterm2_command ` @@ -24,6 +33,9 @@ plugins=(... iterm2) * `iterm2_tab_color_reset` resets the color of iTerm2's current tab back to default. + +For shell integration features see the [official documentation](https://iterm2.com/documentation-shell-integration.html). + ## Contributors - [Aviv Rosenberg](https://github.com/avivrosenberg) diff --git a/plugins/iterm2/iterm2.plugin.zsh b/plugins/iterm2/iterm2.plugin.zsh index 9d8e40bf6..d00232a30 100644 --- a/plugins/iterm2/iterm2.plugin.zsh +++ b/plugins/iterm2/iterm2.plugin.zsh @@ -7,6 +7,17 @@ # This plugin is only relevant if the terminal is iTerm2 on OSX. if [[ "$OSTYPE" == darwin* ]] && [[ -n "$ITERM_SESSION_ID" ]] ; then + # maybe make it the default in the future and allow opting out? + if zstyle -t ':omz:plugins:iterm2' shell-integration; then + # Handle $0 according to the standard: + # https://zdharma-continuum.github.io/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html + 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" + 0="${${(M)0:#/*}:-$PWD/$0}" + + # See official docs: https://iterm2.com/documentation-shell-integration.html + source "${0:A:h}/iterm2_shell_integration.zsh" + fi + ### # Executes an arbitrary iTerm2 command via an escape code sequence. # See https://iterm2.com/documentation-escape-codes.html for all supported commands. diff --git a/plugins/iterm2/iterm2_shell_integration.zsh b/plugins/iterm2/iterm2_shell_integration.zsh new file mode 100644 index 000000000..7871ddded --- /dev/null +++ b/plugins/iterm2/iterm2_shell_integration.zsh @@ -0,0 +1,178 @@ +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +if [[ -o interactive ]]; then + if [ "${ITERM_ENABLE_SHELL_INTEGRATION_WITH_TMUX-}""$TERM" != "tmux-256color" -a "${ITERM_ENABLE_SHELL_INTEGRATION_WITH_TMUX-}""$TERM" != "screen" -a "${ITERM_SHELL_INTEGRATION_INSTALLED-}" = "" -a "$TERM" != linux -a "$TERM" != dumb ]; then + ITERM_SHELL_INTEGRATION_INSTALLED=Yes + ITERM2_SHOULD_DECORATE_PROMPT="1" + # Indicates start of command output. Runs just before command executes. + iterm2_before_cmd_executes() { + if [ "$TERM_PROGRAM" = "iTerm.app" ]; then + printf "\033]133;C;\r\007" + else + printf "\033]133;C;\007" + fi + } + + iterm2_set_user_var() { + printf "\033]1337;SetUserVar=%s=%s\007" "$1" $(printf "%s" "$2" | base64 | tr -d '\n') + } + + # Users can write their own version of this method. It should call + # iterm2_set_user_var but not produce any other output. + # e.g., iterm2_set_user_var currentDirectory $PWD + # Accessible in iTerm2 (in a badge now, elsewhere in the future) as + # \(user.currentDirectory). + whence -v iterm2_print_user_vars > /dev/null 2>&1 + if [ $? -ne 0 ]; then + iterm2_print_user_vars() { + true + } + fi + + iterm2_print_state_data() { + local _iterm2_hostname="${iterm2_hostname-}" + if [ -z "${iterm2_hostname:-}" ]; then + _iterm2_hostname=$(hostname -f 2>/dev/null) + fi + printf "\033]1337;RemoteHost=%s@%s\007" "$USER" "${_iterm2_hostname-}" + printf "\033]1337;CurrentDir=%s\007" "$PWD" + iterm2_print_user_vars + } + + # Report return code of command; runs after command finishes but before prompt + iterm2_after_cmd_executes() { + printf "\033]133;D;%s\007" "$STATUS" + iterm2_print_state_data + } + + # Mark start of prompt + iterm2_prompt_mark() { + printf "\033]133;A\007" + } + + # Mark end of prompt + iterm2_prompt_end() { + printf "\033]133;B\007" + } + + # There are three possible paths in life. + # + # 1) A command is entered at the prompt and you press return. + # The following steps happen: + # * iterm2_preexec is invoked + # * PS1 is set to ITERM2_PRECMD_PS1 + # * ITERM2_SHOULD_DECORATE_PROMPT is set to 1 + # * The command executes (possibly reading or modifying PS1) + # * iterm2_precmd is invoked + # * ITERM2_PRECMD_PS1 is set to PS1 (as modified by command execution) + # * PS1 gets our escape sequences added to it + # * zsh displays your prompt + # * You start entering a command + # + # 2) You press ^C while entering a command at the prompt. + # The following steps happen: + # * (iterm2_preexec is NOT invoked) + # * iterm2_precmd is invoked + # * iterm2_before_cmd_executes is called since we detected that iterm2_preexec was not run + # * (ITERM2_PRECMD_PS1 and PS1 are not messed with, since PS1 already has our escape + # sequences and ITERM2_PRECMD_PS1 already has PS1's original value) + # * zsh displays your prompt + # * You start entering a command + # + # 3) A new shell is born. + # * PS1 has some initial value, either zsh's default or a value set before this script is sourced. + # * iterm2_precmd is invoked + # * ITERM2_SHOULD_DECORATE_PROMPT is initialized to 1 + # * ITERM2_PRECMD_PS1 is set to the initial value of PS1 + # * PS1 gets our escape sequences added to it + # * Your prompt is shown and you may begin entering a command. + # + # Invariants: + # * ITERM2_SHOULD_DECORATE_PROMPT is 1 during and just after command execution, and "" while the prompt is + # shown and until you enter a command and press return. + # * PS1 does not have our escape sequences during command execution + # * After the command executes but before a new one begins, PS1 has escape sequences and + # ITERM2_PRECMD_PS1 has PS1's original value. + iterm2_decorate_prompt() { + # This should be a raw PS1 without iTerm2's stuff. It could be changed during command + # execution. + ITERM2_PRECMD_PS1="$PS1" + ITERM2_SHOULD_DECORATE_PROMPT="" + + # Add our escape sequences just before the prompt is shown. + # Use ITERM2_SQUELCH_MARK for people who can't mdoify PS1 directly, like powerlevel9k users. + # This is gross but I had a heck of a time writing a correct if statetment for zsh 5.0.2. + local PREFIX="" + if [[ $PS1 == *"$(iterm2_prompt_mark)"* ]]; then + PREFIX="" + elif [[ "${ITERM2_SQUELCH_MARK-}" != "" ]]; then + PREFIX="" + else + PREFIX="%{$(iterm2_prompt_mark)%}" + fi + PS1="$PREFIX$PS1%{$(iterm2_prompt_end)%}" + ITERM2_DECORATED_PS1="$PS1" + } + + iterm2_precmd() { + local STATUS="$?" + if [ -z "${ITERM2_SHOULD_DECORATE_PROMPT-}" ]; then + # You pressed ^C while entering a command (iterm2_preexec did not run) + iterm2_before_cmd_executes + if [ "$PS1" != "${ITERM2_DECORATED_PS1-}" ]; then + # PS1 changed, perhaps in another precmd. See issue 9938. + ITERM2_SHOULD_DECORATE_PROMPT="1" + fi + fi + + iterm2_after_cmd_executes "$STATUS" + + if [ -n "$ITERM2_SHOULD_DECORATE_PROMPT" ]; then + iterm2_decorate_prompt + fi + } + + # This is not run if you press ^C while entering a command. + iterm2_preexec() { + # Set PS1 back to its raw value prior to executing the command. + PS1="$ITERM2_PRECMD_PS1" + ITERM2_SHOULD_DECORATE_PROMPT="1" + iterm2_before_cmd_executes + } + + # If hostname -f is slow on your system set iterm2_hostname prior to + # sourcing this script. We know it is fast on macOS so we don't cache + # it. That lets us handle the hostname changing like when you attach + # to a VPN. + if [ -z "${iterm2_hostname-}" ]; then + if [ "$(uname)" != "Darwin" ]; then + iterm2_hostname=`hostname -f 2>/dev/null` + # Some flavors of BSD (i.e. NetBSD and OpenBSD) don't have the -f option. + if [ $? -ne 0 ]; then + iterm2_hostname=`hostname` + fi + fi + fi + + [[ -z ${precmd_functions-} ]] && precmd_functions=() + precmd_functions=($precmd_functions iterm2_precmd) + + [[ -z ${preexec_functions-} ]] && preexec_functions=() + preexec_functions=($preexec_functions iterm2_preexec) + + iterm2_print_state_data + printf "\033]1337;ShellIntegrationVersion=14;shell=zsh\007" + fi +fi diff --git a/plugins/iterm2/update b/plugins/iterm2/update new file mode 100755 index 000000000..da8dae690 --- /dev/null +++ b/plugins/iterm2/update @@ -0,0 +1,4 @@ +#!/bin/sh + +curl -s -L https://iterm2.com/shell_integration/zsh \ + -o iterm2_shell_integration.zsh diff --git a/plugins/jira/README.md b/plugins/jira/README.md index a5633af77..d78ea15a4 100644 --- a/plugins/jira/README.md +++ b/plugins/jira/README.md @@ -14,22 +14,31 @@ In this document, "JIRA" refers to the JIRA issue tracking server, and `jira` re This plugin supplies one command, `jira`, through which all its features are exposed. Most forms of this command open a JIRA page in your web browser. -``` -jira # performs the default action +## Commands + +| Command | Description | +| :------------ | :-------------------------------------------------------- | +| `jira` | Performs the default action | +| `jira new` | Opens a new Jira issue dialogue | +| `jira ABC-123` | Opens an existing issue | +| `jira ABC-123 m` | Opens an existing issue for adding a comment | +| `jira dashboard [rapid_view]` | # opens your JIRA dashboard | +| `jira mine` | Queries for your own issues | +| `jira tempo` | Opens your JIRA Tempo | +| `jira reported [username]` | Queries for issues reported by a user | +| `jira assigned [username]` | Queries for issues assigned to a user | +| `jira branch` | Opens an existing issue matching the current branch name | + + +### Jira Branch usage notes + +The branch name may have prefixes ending in "/": "feature/MP-1234", and also suffixes +starting with "_": "MP-1234_fix_dashboard". In both these cases, the issue opened will be "MP-1234" + +This is also checks if the prefix is in the name, and adds it if not, so: "MP-1234" opens the issue "MP-1234", +"mp-1234" opens the issue "mp-1234", and "1234" opens the issue "MP-1234". + -jira new # opens a new issue -jira dashboard # opens your JIRA dashboard -jira tempo # opens your JIRA Tempo -jira reported [username] # queries for issues reported by a user -jira assigned [username] # queries for issues assigned to a user -jira myissues # queries for you own issues -jira branch # opens an existing issue matching the current branch name - # The branch name may have prefixes ending in "/": "feature/MP-1234", - # and also suffixes starting with "_": "MP-1234_fix_dashboard" - # In both these cases, the issue opened will be "MP-1234" -jira ABC-123 # opens an existing issue -jira ABC-123 m # opens an existing issue for adding a comment -``` #### Debugging usage #### @@ -62,7 +71,9 @@ echo "https://jira.atlassian.com" >> .jira-url * `$JIRA_NAME` - Your JIRA username; used as the default user for `assigned`/`reported` searches * `$JIRA_PREFIX` - Prefix added to issue ID arguments * `$JIRA_RAPID_BOARD` - Set to `true` if you use Rapid Board +* `$JIRA_RAPID_VIEW` - Set the default rapid view; it doesn't work if `$JIRA_RAPID_BOARD` is set to false * `$JIRA_DEFAULT_ACTION` - Action to do when `jira` is called with no arguments; defaults to "new" +* `$JIRA_TEMPO_PATH` - Your JIRA tempo url path; defaults to "/secure/Tempo.jspa" ### Browser ### diff --git a/plugins/jira/_jira b/plugins/jira/_jira index 1ac3eeda3..0e37b7e9d 100644 --- a/plugins/jira/_jira +++ b/plugins/jira/_jira @@ -4,6 +4,7 @@ local -a _1st_arguments _1st_arguments=( 'new:create a new issue' + 'mine:open my issues' 'dashboard:open the dashboard' 'tempo:open the tempo' 'reported:search for issues reported by a user' diff --git a/plugins/jira/jira.plugin.zsh b/plugins/jira/jira.plugin.zsh index 22807e0ae..b6ee9f100 100644 --- a/plugins/jira/jira.plugin.zsh +++ b/plugins/jira/jira.plugin.zsh @@ -44,25 +44,31 @@ function jira() { open_command "${jira_url}/secure/CreateIssue!default.jspa" elif [[ "$action" == "assigned" || "$action" == "reported" ]]; then _jira_query ${@:-$action} - elif [[ "$action" == "myissues" ]]; then + elif [[ "$action" == "mine" ]]; then echo "Opening my issues" open_command "${jira_url}/issues/?filter=-1" elif [[ "$action" == "dashboard" ]]; then echo "Opening dashboard" if [[ "$JIRA_RAPID_BOARD" == "true" ]]; then - open_command "${jira_url}/secure/RapidBoard.jspa" + _jira_rapid_board ${@} else open_command "${jira_url}/secure/Dashboard.jspa" fi elif [[ "$action" == "tempo" ]]; then echo "Opening tempo" - open_command "${jira_url}/secure/Tempo.jspa" + if [[ -n "$JIRA_TEMPO_PATH" ]]; then + open_command "${jira_url}${JIRA_TEMPO_PATH}" + else + open_command "${jira_url}/secure/Tempo.jspa" + fi elif [[ "$action" == "dumpconfig" ]]; then echo "JIRA_URL=$jira_url" echo "JIRA_PREFIX=$jira_prefix" echo "JIRA_NAME=$JIRA_NAME" + echo "JIRA_RAPID_VIEW=$JIRA_RAPID_VIEW" echo "JIRA_RAPID_BOARD=$JIRA_RAPID_BOARD" echo "JIRA_DEFAULT_ACTION=$JIRA_DEFAULT_ACTION" + echo "JIRA_TEMPO_PATH=$JIRA_TEMPO_PATH" else # Anything that doesn't match a special action is considered an issue name # but `branch` is a special case that will parse the current git branch @@ -74,8 +80,14 @@ function jira() { issue_arg=${issue_arg##*/} # Strip suffixes starting with _ issue_arg=(${(s:_:)issue_arg}) - issue_arg=${issue_arg[1]} - if [[ "$issue_arg" = ${jira_prefix}* ]]; then + # If there is only one part, it means that there is a different delimiter. Try with - + if [[ ${#issue_arg[@]} = 1 && ${issue_arg} == *-* ]]; then + issue_arg=(${(s:-:)issue_arg}) + issue_arg="${issue_arg[1]}-${issue_arg[2]}" + else + issue_arg=${issue_arg[1]} + fi + if [[ "${issue_arg:l}" = ${jira_prefix:l}* ]]; then issue="${issue_arg}" else issue="${jira_prefix}${issue_arg}" @@ -107,6 +119,16 @@ Valid options, in order of precedence: EOF } +function _jira_rapid_board() { + rapid_view=${2:=$JIRA_RAPID_VIEW} + + if [[ -z $rapid_view ]]; then + open_command "${jira_url}/secure/RapidBoard.jspa" + else + open_command "${jira_url}/secure/RapidBoard.jspa?rapidView=$rapid_view" + fi +} + function _jira_query() { emulate -L zsh local verb="$1" diff --git a/plugins/juju/README.md b/plugins/juju/README.md index f0c65309c..6ee333f50 100644 --- a/plugins/juju/README.md +++ b/plugins/juju/README.md @@ -126,5 +126,7 @@ Naming convention: - `jaddr [unit_num]`: display app or unit IP address. - `jreld `: display app and unit relation data. - `jclean`: destroy all controllers +- `jcontroller`: display the controller your are connected to. +- `jmodel`: display the model your are connected to. - `wjst [interval_secs] [args_for_watch]`: watch juju status, with optional interval (default: 5s); you may pass additional arguments to `watch`. diff --git a/plugins/juju/juju.plugin.zsh b/plugins/juju/juju.plugin.zsh index be8a2c7ae..a82ebaf84 100644 --- a/plugins/juju/juju.plugin.zsh +++ b/plugins/juju/juju.plugin.zsh @@ -98,7 +98,7 @@ jaddr() { elif [[ $# -eq 2 ]]; then # Get unit address juju status "$1/$2" --format=json \ - | jq -r ".applications.\"$1\".units.\"$1/$2\".address" + | jq -r ".applications.\"$1\".units.\"$1/$2\" | .address // .\"public-address\"" else echo "Invalid number of arguments." echo "Usage: jaddr []" @@ -163,10 +163,40 @@ jreld() { juju run "relation-get -r $relid - $2" --unit $2/$3 } +# Return Juju current controller +jcontroller() { + local controller="$(awk '/current-controller/ {print $2}' ~/.local/share/juju/controllers.yaml)" + if [[ -z "$controller" ]]; then + return 1 + fi + + echo $controller + return 0 +} + +# Return Juju current model +jmodel() { + local yqbin="$(whereis yq | awk '{print $2}')" + + if [[ -z "$yqbin" ]]; then + echo "--" + return 1 + fi + + local model="$(yq e ".controllers.$(jcontroller).current-model" < ~/.local/share/juju/models.yaml | cut -d/ -f2)" + + if [[ -z "$model" ]]; then + echo "--" + return 1 + fi + + echo $model + return 0 +} + # Watch juju status, with optional interval (default: 5 sec) wjst() { local interval="${1:-5}" shift $(( $# > 0 )) watch -n "$interval" --color juju status --relations --color "$@" } - diff --git a/plugins/jump/jump.plugin.zsh b/plugins/jump/jump.plugin.zsh index c2da1144e..829c9d9cb 100644 --- a/plugins/jump/jump.plugin.zsh +++ b/plugins/jump/jump.plugin.zsh @@ -35,12 +35,11 @@ marks() { max=${#link:t} fi done - local printf_markname_template="$(printf -- "%%%us " "$max")" + local printf_markname_template="$(printf -- "%%%us" "$max")" for link in $MARKPATH/{,.}*(@N); do - local markname="$fg[cyan]${link:t}$reset_color" + local markname="$fg[cyan]$(printf -- "$printf_markname_template" "${link:t}")$reset_color" local markpath="$fg[blue]$(readlink $link)$reset_color" - printf -- "$printf_markname_template" "$markname" - printf -- "-> %s\n" "$markpath" + printf -- "%s -> %s\n" "$markname" "$markpath" done } diff --git a/plugins/kind/README.md b/plugins/kind/README.md new file mode 100644 index 000000000..49024648d --- /dev/null +++ b/plugins/kind/README.md @@ -0,0 +1,22 @@ +# Kind plugin + +This plugin adds completion for the [Kind](https://kind.sigs.k8s.io/) tool, as well +as a few aliases for easier use. + +To use it, add `kind` to the plugins array in your zshrc file: + +```zsh +plugins=(... kind) +``` + +## Aliases + +| Alias | Command | +| ------- | ---------------------------- | +| `kicc` | `kind create cluster` | +| `kiccn` | `kind create cluster --name` | +| `kigc` | `kind get clusters` | +| `kidc` | `kind delete cluster` | +| `kidcn` | `kind delete cluster --name` | +| `kidca` | `kind delete clusters -A` | +| `kigk` | `kind get kubeconfig` | diff --git a/plugins/kind/kind.plugin.zsh b/plugins/kind/kind.plugin.zsh new file mode 100644 index 000000000..183eb7bd6 --- /dev/null +++ b/plugins/kind/kind.plugin.zsh @@ -0,0 +1,23 @@ +if (( ! $+commands[kind] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `kind`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_kind" ]]; then + typeset -g -A _comps + autoload -Uz _kind + _comps[kind]=_kind +fi + +# Generate and load kind completion +kind completion zsh >! "$ZSH_CACHE_DIR/completions/_kind" &| + +# Register aliases +alias kicc="kind create cluster" +alias kiccn="kind create cluster --name" +alias kigc="kind get clusters" +alias kidc="kind delete cluster" +alias kidcn="kind delete cluster --name" +alias kidca="kind delete clusters -A" +alias kigk="kind get kubeconfig" diff --git a/plugins/kitchen/_kitchen b/plugins/kitchen/_kitchen index d93d93d78..64c01e395 100644 --- a/plugins/kitchen/_kitchen +++ b/plugins/kitchen/_kitchen @@ -1,6 +1,6 @@ #compdef kitchen # ------------------------------------------------------------------------------ -# Copyright (c) 2014 Github zsh-users - https://github.com/zsh-users +# Copyright (c) 2014 GitHub zsh-users - https://github.com/zsh-users # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/plugins/kubectl/kubectl.plugin.zsh b/plugins/kubectl/kubectl.plugin.zsh index 095d2b328..0dd4e691a 100644 --- a/plugins/kubectl/kubectl.plugin.zsh +++ b/plugins/kubectl/kubectl.plugin.zsh @@ -1,15 +1,17 @@ -if (( $+commands[kubectl] )); then - # If the completion file does not exist, generate it and then source it - # Otherwise, source it and regenerate in the background - if [[ ! -f "$ZSH_CACHE_DIR/completions/_kubectl" ]]; then - kubectl completion zsh | tee "$ZSH_CACHE_DIR/completions/_kubectl" >/dev/null - source "$ZSH_CACHE_DIR/completions/_kubectl" - else - source "$ZSH_CACHE_DIR/completions/_kubectl" - kubectl completion zsh | tee "$ZSH_CACHE_DIR/completions/_kubectl" >/dev/null &| - fi +if (( ! $+commands[kubectl] )); then + return fi +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `kubectl`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_kubectl" ]]; then + typeset -g -A _comps + autoload -Uz _kubectl + _comps[kubectl]=_kubectl +fi + +kubectl completion zsh 2> /dev/null >| "$ZSH_CACHE_DIR/completions/_kubectl" &| + # This command is used a LOT both below and in daily life alias k=kubectl @@ -160,6 +162,7 @@ alias kdelsa="kubectl delete sa" # DaemonSet management. alias kgds='kubectl get daemonset' +alias kgdsa='kubectl get daemonset --all-namespaces' alias kgdsw='kgds --watch' alias keds='kubectl edit daemonset' alias kdds='kubectl describe daemonset' diff --git a/plugins/lando/README.md b/plugins/lando/README.md index 928a42bca..2f881cf3d 100644 --- a/plugins/lando/README.md +++ b/plugins/lando/README.md @@ -8,7 +8,7 @@ To use it, add `lando` to the plugins array in your zshrc file: plugins=(... lando) ``` -## ALIASES: +## Wrapped Commands | Alias | Description | |:----------:|:----------------:| @@ -17,19 +17,38 @@ plugins=(... lando) | `drush` | `lando drush` | | `gulp` | `lando gulp` | | `npm` | `lando npm` | +| `php` | `lando php` | | `wp` | `lando wp` | | `yarn` | `lando yarn` | +More or different commands can be wrapped by setting the `LANDO_ZSH_WRAPPED_COMMANDS` setting, see [Settings](#settings) below. + ## How It Works: This plugin removes the requirement to type `lando` before a command. It utilizes the lando version of supported commands run within directories with the following criteria: + - The `.lando.yml` file is found in the current directory or any parent directory within `$LANDO_ZSH_SITES_DIRECTORY`. - The current directory is within `$LANDO_ZSH_SITES_DIRECTORY` but is not `$LANDO_ZSH_SITES_DIRECTORY` itself. +- If the command is not a part of the commands available in the lando environment, it will run the command without `lando`. ## Settings: -- `LANDO_ZSH_SITES_DIRECTORY`: The plugin will stop searching through parents for `CONFIG_FILE` once it hits this directory. -- `LANDO_ZSH_CONFIG_FILE`: The plugin will check to see if this provided file exists to check for presence of Lando. +> NOTE: these settings must be set *before* the plugin is loaded, and any changes require a restart of the shell to be applied. + +- `LANDO_ZSH_SITES_DIRECTORY`: The plugin will stop searching through parents for `CONFIG_FILE` once it hits this directory: + ```sh + LANDO_ZSH_SITES_DIRECTORY="$HOME/Code" + ``` + +- `LANDO_ZSH_CONFIG_FILE`: The plugin will check to see if this provided file exists to check for presence of Lando: + ```sh + LANDO_ZSH_CONFIG_FILE=".lando.dev.yml" + ``` + +- `LANDO_ZSH_WRAPPED_COMMANDS`: The list of commands to wrap, as a string of commands separated by whitespace: + ```sh + LANDO_ZSH_WRAPPED_COMMANDS="mysql php composer test artisan" + ``` ## Author: diff --git a/plugins/lando/lando.plugin.zsh b/plugins/lando/lando.plugin.zsh index af53e7e5a..ee796d212 100644 --- a/plugins/lando/lando.plugin.zsh +++ b/plugins/lando/lando.plugin.zsh @@ -1,25 +1,36 @@ # Settings : ${LANDO_ZSH_SITES_DIRECTORY:="$HOME/Sites"} : ${LANDO_ZSH_CONFIG_FILE:=.lando.yml} +: ${LANDO_ZSH_WRAPPED_COMMANDS:=" + artisan + composer + drush + gulp + npm + php + wp + yarn +"} # Enable multiple commands with lando. -function artisan \ - composer \ - drush \ - gulp \ - npm \ - php \ - wp \ - yarn { - if checkForLandoFile; then - lando "$0" "$@" +function ${=LANDO_ZSH_WRAPPED_COMMANDS} { + # If the lando task is available in `lando --help`, then it means: + # + # 1. `lando` is in a project with a `.lando.yml` file. + # 2. The lando task is available for lando, based on the .lando.yml config file. + # + # This has a penalty of about 250ms, so we still want to check if the lando file + # exists before, which is the fast path. If it exists, checking help output is + # still faster than running the command and failing. + if _lando_file_exists && lando --help 2>&1 | command grep -Eq "^ +lando $0 "; then + command lando "$0" "$@" else command "$0" "$@" fi } # Check for the file in the current and parent directories. -checkForLandoFile() { +_lando_file_exists() { # Only bother checking for lando within the Sites directory. if [[ "$PWD/" != "$LANDO_ZSH_SITES_DIRECTORY"/* ]]; then # Not within $LANDO_ZSH_SITES_DIRECTORY @@ -38,4 +49,4 @@ checkForLandoFile() { # Could not find $LANDO_ZSH_CONFIG_FILE in the current directory # or in any of its parents up to $LANDO_ZSH_SITES_DIRECTORY. return 1 -} \ No newline at end of file +} diff --git a/plugins/last-working-dir/last-working-dir.plugin.zsh b/plugins/last-working-dir/last-working-dir.plugin.zsh index 905a02a70..684972cc1 100644 --- a/plugins/last-working-dir/last-working-dir.plugin.zsh +++ b/plugins/last-working-dir/last-working-dir.plugin.zsh @@ -9,7 +9,7 @@ chpwd_last_working_dir() { [[ "$ZSH_SUBSHELL" -eq 0 ]] || return 0 # Add ".$SSH_USER" suffix to cache file if $SSH_USER is set and non-empty local cache_file="$ZSH_CACHE_DIR/last-working-dir${SSH_USER:+.$SSH_USER}" - pwd >| "$cache_file" + builtin pwd >| "$cache_file" } # Changes directory to the last working directory diff --git a/plugins/lol/README.md b/plugins/lol/README.md index ea6b0c3b8..b45513b35 100644 --- a/plugins/lol/README.md +++ b/plugins/lol/README.md @@ -49,7 +49,7 @@ plugins=(... lol) | `violenz` | `git rebase` | | `visible` | `echo` | | `wtf` | `dmesg` | -| `yolo` | `git commit -m "$(curl -s http://whatthecommit.com/index.txt)"` | +| `yolo` | `git commit -m "$(curl -s https://whatthecommit.com/index.txt)"` | ## Usage Examples @@ -66,6 +66,6 @@ nowai u=r,go= some.file # ssh root@catserver.org pwned root@catserver.org -# git commit -m "$(curl -s http://whatthecommit.com/index.txt)" +# git commit -m "$(curl -s https://whatthecommit.com/index.txt)" yolo ``` diff --git a/plugins/lol/lol.plugin.zsh b/plugins/lol/lol.plugin.zsh index 3c30259a1..585f96e4f 100644 --- a/plugins/lol/lol.plugin.zsh +++ b/plugins/lol/lol.plugin.zsh @@ -45,7 +45,7 @@ alias bringz='git pull' alias chicken='git add' alias oanward='git commit -m' alias ooanward='git commit -am' -alias yolo='git commit -m "$(curl -s http://whatthecommit.com/index.txt)"' +alias yolo='git commit -m "$(curl -s https://whatthecommit.com/index.txt)"' alias letcat='git checkout' alias violenz='git rebase' diff --git a/plugins/lpass/_lpass b/plugins/lpass/_lpass index e6193a22d..621a7bcd7 100644 --- a/plugins/lpass/_lpass +++ b/plugins/lpass/_lpass @@ -106,7 +106,7 @@ _lpass() { generic_options+=('--color=[Color: auto | never | always]') fi if [ "$has_interactive" -eq 1 ]; then - generic_options+=("--non-interactive[Use stardard input instead of $EDITOR]") + generic_options+=("--non-interactive[Use standard input instead of $EDITOR]") fi _arguments $generic_options fi diff --git a/plugins/macos/README.md b/plugins/macos/README.md index 1bc4244a4..1cb9b395d 100644 --- a/plugins/macos/README.md +++ b/plugins/macos/README.md @@ -25,7 +25,7 @@ Original author: [Sorin Ionescu](https://github.com/sorin-ionescu) | `pxd` | Return the current Xcode project directory | | `cdx` | `cd` to the current Xcode project directory | | `quick-look` | Quick-Look a specified file | -| `man-preview` | Open a specified man page in Preview app | +| `man-preview` | Open man pages in Preview app | | `showfiles` | Show hidden files in Finder | | `hidefiles` | Hide the hidden files in Finder | | `itunes` | _DEPRECATED_. Use `music` from macOS Catalina on | diff --git a/plugins/macos/macos.plugin.zsh b/plugins/macos/macos.plugin.zsh index b540eecb5..e27d412c8 100644 --- a/plugins/macos/macos.plugin.zsh +++ b/plugins/macos/macos.plugin.zsh @@ -224,8 +224,10 @@ function quick-look() { } function man-preview() { - # Don't let Preview.app steal focus if the man page doesn't exist - man -w "$@" &>/dev/null && man -t "$@" | open -f -a Preview || man "$@" + local page + for page in "${(@f)"$(man -w $@)"}"; do + command mandoc -Tpdf $page | open -f -a Preview + done } compdef _man man-preview diff --git a/plugins/macos/spotify b/plugins/macos/spotify index 491a60686..ae42db425 100644 --- a/plugins/macos/spotify +++ b/plugins/macos/spotify @@ -1,7 +1,7 @@ #!/usr/bin/env bash function spotify() { -# Copyright (c) 2012--2019 Harish Narayanan +# Copyright (c) 2012--2023 Harish Narayanan # # Contains numerous helpful contributions from Jorge Colindres, Thomas # Pritchard, iLan Epstein, Gabriele Bonetti, Sean Heller, Eric Martin @@ -35,6 +35,9 @@ if ! [[ -f "${USER_CONFIG_FILE}" ]]; then fi source "${USER_CONFIG_FILE}"; +# Set the percent change in volume for vol up and vol down +VOL_INCREMENT=10 + showAPIHelp() { echo; echo "Connecting to Spotify's API:"; @@ -43,7 +46,7 @@ showAPIHelp() { echo " find music by name. It is very likely you want this feature!"; echo; echo " To get this to work, you need to sign up (or in) and create an 'Application' at:"; - echo " https://developer.spotify.com/my-applications/#!/applications/create"; + echo " https://developer.spotify.com/dashboard/create"; echo; echo " Once you've created an application, find the 'Client ID' and 'Client Secret'"; echo " values, and enter them into your shpotify config file at '${USER_CONFIG_FILE}'"; @@ -170,12 +173,12 @@ while [ $# -gt 0 ]; do if [ -z "${CLIENT_ID}" ]; then cecho "Invalid Client ID, please update ${USER_CONFIG_FILE}"; showAPIHelp; - return 1 + return 1; fi if [ -z "${CLIENT_SECRET}" ]; then cecho "Invalid Client Secret, please update ${USER_CONFIG_FILE}"; showAPIHelp; - return 1 + return 1; fi SHPOTIFY_CREDENTIALS=$(printf "${CLIENT_ID}:${CLIENT_SECRET}" | base64 | tr -d "\n"|tr -d '\r'); SPOTIFY_PLAY_URI=""; @@ -198,7 +201,7 @@ while [ $# -gt 0 ]; do fi SPOTIFY_ACCESS_TOKEN=$( \ printf "${SPOTIFY_TOKEN_RESPONSE_DATA}" \ - | grep -E -o '"access_token":".*",' \ + | command grep -E -o '"access_token":".*",' \ | sed 's/"access_token"://g' \ | sed 's/"//g' \ | sed 's/,.*//g' \ @@ -219,9 +222,8 @@ while [ $# -gt 0 ]; do -H "Accept: application/json" \ --data-urlencode "q=$Q" \ -d "type=$type&limit=1&offset=0" \ - | grep -E -o "spotify:$type:[a-zA-Z0-9]+" -m 1 + | command grep -E -o "spotify:$type:[a-zA-Z0-9]+" -m 1 ) - echo "play uri: ${SPOTIFY_PLAY_URI}" } case $2 in @@ -235,11 +237,11 @@ while [ $# -gt 0 ]; do results=$( \ curl -s -G $SPOTIFY_SEARCH_API --data-urlencode "q=$Q" -d "type=playlist&limit=10&offset=0" -H "Accept: application/json" -H "Authorization: Bearer ${SPOTIFY_ACCESS_TOKEN}" \ - | grep -E -o "spotify:playlist:[a-zA-Z0-9]+" -m 10 \ + | command grep -E -o "spotify:playlist:[a-zA-Z0-9]+" -m 10 \ ) count=$( \ - echo "$results" | grep -c "spotify:playlist" \ + echo "$results" | command grep -c "spotify:playlist" \ ) if [ "$count" -gt 0 ]; then @@ -333,16 +335,16 @@ while [ $# -gt 0 ]; do cecho "Current Spotify volume level is $vol."; break ; elif [ "$2" = "up" ]; then - if [ $vol -le 90 ]; then - newvol=$(( vol+10 )); + if [ $vol -le $(( 100-$VOL_INCREMENT )) ]; then + newvol=$(( vol+$VOL_INCREMENT )); cecho "Increasing Spotify volume to $newvol."; else newvol=100; cecho "Spotify volume level is at max."; fi elif [ "$2" = "down" ]; then - if [ $vol -ge 10 ]; then - newvol=$(( vol-10 )); + if [ $vol -ge $(( $VOL_INCREMENT )) ]; then + newvol=$(( vol-$VOL_INCREMENT )); cecho "Reducing Spotify volume to $newvol."; else newvol=0; @@ -354,11 +356,11 @@ while [ $# -gt 0 ]; do else echo "Improper use of 'vol' command" echo "The 'vol' command should be used as follows:" - echo " vol up # Increases the volume by 10%."; - echo " vol down # Decreases the volume by 10%."; + echo " vol up # Increases the volume by $VOL_INCREMENT%."; + echo " vol down # Decreases the volume by $VOL_INCREMENT%."; echo " vol [amount] # Sets the volume to an amount between 0 and 100."; echo " vol # Shows the current Spotify volume."; - return 1 + return 1; fi osascript -e "tell application \"Spotify\" to set sound volume to $newvol"; @@ -468,10 +470,9 @@ while [ $# -gt 0 ]; do "help" ) showHelp; break ;; - * ) showHelp; - return 1 ;; + return 1; esac done diff --git a/plugins/marked2/marked2.plugin.zsh b/plugins/marked2/marked2.plugin.zsh index 56863ade5..45f4b65c1 100644 --- a/plugins/marked2/marked2.plugin.zsh +++ b/plugins/marked2/marked2.plugin.zsh @@ -3,10 +3,5 @@ # If marked is passed a file, open it in Marked # function marked() { - if [ "$1" ] - then - open -a "marked 2.app" "$1" - else - open -a "marked 2.app" - fi + open -a "marked 2.app" "$1" } diff --git a/plugins/marktext/README.md b/plugins/marktext/README.md new file mode 100644 index 000000000..71d287451 --- /dev/null +++ b/plugins/marktext/README.md @@ -0,0 +1,17 @@ +## marktext + +Plugin for MarkText, a previewer for Markdown files on Mac OS X + +### Requirements + + * [MarkText](https://github.com/marktext/marktext) + +### Usage + + * If `marktext` is called without an argument, open MarkText + + * If `marktext` is passed a file, open it in MarkText + +### Credits + + * just copied from plugins/marked2, all credits to marked2 plugin author diff --git a/plugins/marktext/marktext.plugin.zsh b/plugins/marktext/marktext.plugin.zsh new file mode 100644 index 000000000..1da85bcca --- /dev/null +++ b/plugins/marktext/marktext.plugin.zsh @@ -0,0 +1,7 @@ +# +# If marktext is called without an argument, open MarkText +# If marktext is passed a file, open it in MarkText +# +function marktext() { + open -a "MarkText.app" "$1" +} diff --git a/plugins/mongo-atlas/README.md b/plugins/mongo-atlas/README.md new file mode 100644 index 000000000..ef1b5e0d2 --- /dev/null +++ b/plugins/mongo-atlas/README.md @@ -0,0 +1,10 @@ +# MongoDB Atlas plugin + +This plugin adds completion for [Atlas](https://www.mongodb.com/docs/atlas/cli/stable/) a command line interface built specifically for +MongoDB Atlas. + +To use it, add `mongo-atlas` to the plugins array in your zshrc file: + +```zsh +plugins=(... mongo-atlas) +``` diff --git a/plugins/mongo-atlas/mongo-atlas.plugin.zsh b/plugins/mongo-atlas/mongo-atlas.plugin.zsh new file mode 100644 index 000000000..6762c909e --- /dev/null +++ b/plugins/mongo-atlas/mongo-atlas.plugin.zsh @@ -0,0 +1,14 @@ +# Autocompletion for the Mongo Atlas CLI (atlas). +if (( ! $+commands[atlas] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `atlas`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_atlas" ]]; then + typeset -g -A _comps + autoload -Uz _atlas + _comps[atlas]=_atlas +fi + +atlas completion zsh >| "$ZSH_CACHE_DIR/completions/atlas" &| diff --git a/plugins/mvn/README.md b/plugins/mvn/README.md index 815dfd57c..4181fedc5 100644 --- a/plugins/mvn/README.md +++ b/plugins/mvn/README.md @@ -33,7 +33,7 @@ if it's found, or the mvn command otherwise. | `mvnct` | `mvn clean test` | | `mvncv` | `mvn clean verify` | | `mvncvst` | `mvn clean verify -DskipTests` | -| `mvnd` | `mvn deploy` | +| `mvndp` | `mvn deploy` | | `mvndocs` | `mvn dependency:resolve -Dclassifier=javadoc` | | `mvndt` | `mvn dependency:tree` | | `mvne` | `mvn eclipse:eclipse` | diff --git a/plugins/mvn/mvn.plugin.zsh b/plugins/mvn/mvn.plugin.zsh index 1b9141f21..a569a87fa 100644 --- a/plugins/mvn/mvn.plugin.zsh +++ b/plugins/mvn/mvn.plugin.zsh @@ -62,7 +62,7 @@ alias mvncp='mvn clean package' alias mvnct='mvn clean test' alias mvncv='mvn clean verify' alias mvncvst='mvn clean verify -DskipTests' -alias mvnd='mvn deploy' +alias mvndp='mvn deploy' alias mvndocs='mvn dependency:resolve -Dclassifier=javadoc' alias mvndt='mvn dependency:tree' alias mvne='mvn eclipse:eclipse' @@ -196,7 +196,7 @@ function listMavenCompletions { # spring-boot spring-boot:run spring-boot:repackage # quarkus - quarkus:dev quarkus:list-extensions quarkus:add-extension quarkus:add-extensions quarkus:generate-config quarkus:help + quarkus:dev quarkus:list-extensions quarkus:add-extension quarkus:add-extensions quarkus:remove-extension quarkus:remove-extensions quarkus:generate-config quarkus:help # exec exec:exec exec:java # versions @@ -283,9 +283,11 @@ function listMavenCompletions { toolchain:toolchain #liberty liberty:clean-server liberty:compile-jsp liberty:configure-arquillian liberty:create-server liberty:debug liberty:debug-server liberty:deploy liberty:dev liberty:display-url liberty:dump-server liberty:install-apps liberty:install-feature liberty:install-server liberty:java-dump-server liberty:package-server liberty:run liberty:run-server liberty:server-status liberty:start liberty:start-server liberty:status liberty:stop liberty:stop-server liberty:test-start-server liberty:test-stop-server liberty:undeploy liberty:uninstall-feature + # vaadin + vaadin:prepare-frontend vaadin:build-frontend vaadin:clean-frontend vaadin:dance # options - "-Dmaven.test.skip=true" -DskipTests -DskipITs -Dmaven.surefire.debug -DenableCiProfile "-Dpmd.skip=true" "-Dcheckstyle.skip=true" "-Dtycho.mode=maven" "-Dmaven.test.failure.ignore=true" "-DgroupId=" "-DartifactId=" "-Dversion=" "-Dpackaging=jar" "-Dfile=" + "-Dmaven.test.skip=true" -DskipTests -DskipITs -Dmaven.surefire.debug -DenableCiProfile "-Dpmd.skip=true" "-Dcheckstyle.skip=true" "-Dtycho.mode=maven" "-Dmaven.test.failure.ignore=true" "-DgroupId=" "-DartifactId=" "-Dversion=" "-Dpackaging=jar" "-Dfile=" "-Dextensions=" # arguments -am --also-make diff --git a/plugins/nats/README.md b/plugins/nats/README.md new file mode 100644 index 000000000..0ea26fca1 --- /dev/null +++ b/plugins/nats/README.md @@ -0,0 +1,14 @@ +# NATS plugin + +This plugin adds completion for several tools from [NATS](https://nats.io/). + +- [`nsc`](https://github.com/nats-io/nsc) +- [`natscli`](https://github.com/nats-io/natscli) + +To use it, add `nats` to the plugins array in your zshrc file: + +```zsh +plugins=(... nats) +``` + +This plugin does not add any aliases. diff --git a/plugins/nats/nats.plugin.zsh b/plugins/nats/nats.plugin.zsh new file mode 100644 index 000000000..8b95b07c6 --- /dev/null +++ b/plugins/nats/nats.plugin.zsh @@ -0,0 +1,23 @@ +if (( $+commands[nsc] )); then + # If the completion file doesn't exist yet, we need to autoload it and + # bind it to `nsc`. Otherwise, compinit will have already done that. + if [[ ! -f "$ZSH_CACHE_DIR/completions/_nsc" ]]; then + typeset -g -A _comps + autoload -Uz _nsc + _comps[nsc]=_nsc + fi + + nsc completion zsh >| "$ZSH_CACHE_DIR/completions/_nsc" &| +fi + +if (( $+commands[nats] )); then + # If the completion file doesn't exist yet, we need to autoload it and + # bind it to `nats`. Otherwise, compinit will have already done that. + if [[ ! -f "$ZSH_CACHE_DIR/completions/_nats" ]]; then + typeset -g -A _comps + autoload -Uz _nats + _comps[nats]=_nats + fi + + nats --completion-script-zsh >| "$ZSH_CACHE_DIR/completions/_nats" &| +fi diff --git a/plugins/ng/_ng b/plugins/ng/_ng index 9c96cf7e3..86c6ce187 100644 --- a/plugins/ng/_ng +++ b/plugins/ng/_ng @@ -46,7 +46,7 @@ elif (( CURRENT == 3 )); then # ... # } # } - # In abscence of a proper JSON parser, just grab the lines with + # In absence of a proper JSON parser, just grab the lines with # a 2-space indentation and only the stuff inside quotes local -a projects projects=(${(@f)"$(ng config projects 2>/dev/null | sed -n 's/^ "\([^"]\+\)".*$/\1/p')"}) diff --git a/plugins/nodenv/README.md b/plugins/nodenv/README.md new file mode 100644 index 000000000..550597025 --- /dev/null +++ b/plugins/nodenv/README.md @@ -0,0 +1,20 @@ +# nodenv plugin + +The primary job of this plugin is to provide `nodenv_prompt_info` which can be added to your theme to include Node +version information into your prompt. + +To use it, add `nodenv` to the plugins array in your zshrc file: + +```zsh +plugins=(... nodenv) +``` + +## Functions + +* `nodenv_prompt_info`: displays the Node version in use by nodenv; or the global Node + version, if nodenv wasn't found. You can use this function in your prompt by adding + `$(nodenv_prompt_info)` to PROMPT or RPROMPT: + + ```zsh + RPROMPT='$(nodenv_prompt_info)' + ``` diff --git a/plugins/nodenv/nodenv.plugin.zsh b/plugins/nodenv/nodenv.plugin.zsh new file mode 100644 index 000000000..79a4ffbb5 --- /dev/null +++ b/plugins/nodenv/nodenv.plugin.zsh @@ -0,0 +1,43 @@ +# This plugin loads nodenv into the current shell and provides prompt info via +# the 'nodenv_prompt_info' function. + +FOUND_NODENV=${+commands[nodenv]} + +if [[ $FOUND_NODENV -ne 1 ]]; then + nodenvdirs=( + "$HOME/.nodenv" + "/usr/local/nodenv" + "/opt/nodenv" + "/usr/local/opt/nodenv" + ) + for dir in $nodenvdirs; do + if [[ -d "${dir}/bin" ]]; then + export PATH="$PATH:${dir}/bin" + FOUND_NODENV=1 + break + fi + done + + if [[ $FOUND_NODENV -ne 1 ]]; then + if (( $+commands[brew] )) && dir=$(brew --prefix nodenv 2>/dev/null); then + if [[ -d "${dir}/bin" ]]; then + export PATH="$PATH:${dir}/bin" + FOUND_NODENV=1 + fi + fi + fi +fi + +if [[ $FOUND_NODENV -eq 1 ]]; then + eval "$(nodenv init --no-rehash - zsh)" + function nodenv_prompt_info() { + nodenv version-name 2>/dev/null + } +else + # fallback to system node + function nodenv_prompt_info() { + echo "system: $(node -v 2>&1 | cut -c 2-)" + } +fi + +unset FOUND_NODENV nodenvdirs dir diff --git a/plugins/npm/README.md b/plugins/npm/README.md index 8eafc6d61..7848a1290 100644 --- a/plugins/npm/README.md +++ b/plugins/npm/README.md @@ -29,6 +29,8 @@ plugins=(... npm) | `npmI` | `npm init` | Run npm init | | `npmi` | `npm info` | Run npm info | | `npmSe` | `npm search` | Run npm search | +| `npmrd` | `npm run dev` | Run npm run dev | +| `npmrb` | `npm run build` | Run npm run build | ## `npm install` / `npm uninstall` toggle diff --git a/plugins/npm/npm.plugin.zsh b/plugins/npm/npm.plugin.zsh index 6c768d614..23377b085 100644 --- a/plugins/npm/npm.plugin.zsh +++ b/plugins/npm/npm.plugin.zsh @@ -1,5 +1,5 @@ (( $+commands[npm] )) && { - rm -f "${ZSH_CACHE_DIR:-$ZSH/cache}/npm_completion" + command rm -f "${ZSH_CACHE_DIR:-$ZSH/cache}/npm_completion" _npm_completion() { local si=$IFS @@ -70,6 +70,12 @@ alias npmi="npm info" # Run npm search alias npmSe="npm search" +# Run npm run dev +alias npmrd="npm run dev" + +# Run npm run build +alias npmrb="npm run build" + npm_toggle_install_uninstall() { # Look up to the previous 2 history commands local line diff --git a/plugins/nvm/README.md b/plugins/nvm/README.md index a8bc34ae7..b5ef221d3 100644 --- a/plugins/nvm/README.md +++ b/plugins/nvm/README.md @@ -1,7 +1,7 @@ # nvm plugin -This plugin adds autocompletions for [nvm](https://github.com/nvm-sh/nvm) — a Node.js version manager. -It also automatically sources nvm, so you don't need to do it manually in your `.zshrc`. +This plugin adds autocompletions for [nvm](https://github.com/nvm-sh/nvm) — a Node.js version manager. It also +automatically sources nvm, so you don't need to do it manually in your `.zshrc`. To use it, add `nvm` to the plugins array of your zshrc file: @@ -21,14 +21,38 @@ These settings should go in your zshrc file, before Oh My Zsh is sourced: [Homebrew is installed in `/opt/homebrew`](https://docs.brew.sh/Installation). To get the directory where nvm has been installed, regardless of chip architecture, use `NVM_HOMEBREW=$(brew --prefix nvm)`. -- **`NVM_LAZY`**: if you want the plugin to defer the load of nvm to speed-up the start of your zsh session, - set `NVM_LAZY` to `1`. This will use the `--no-use` parameter when loading nvm, and will create a function - for `node`, `npm`, `yarn`, and the command(s) specified by `NVM_LAZY_CMD`, so when you call either of them, - nvm will load with `nvm use default`. +## Customization -- **`NVM_LAZY_CMD`**: if you want additional command(s) to trigger lazy loading of nvm, set `NVM_LAZY_CMD` to - the command or an array of the commands. +#### Lazy startup -- **`NVM_AUTOLOAD`**: if `NVM_AUTOLOAD` is set to `1`, the plugin will automatically load a node version when - if finds a [`.nvmrc` file](https://github.com/nvm-sh/nvm#nvmrc) in the current working directory indicating - which node version to load. +This option will help you to defer nvm's load until you use it to speed-up your zsh startup. This will source +nvm script only when using it, and will create a function for `node`, `npm`, `npx`, `pnpm`, `yarn`, and the +command(s) specified by `lazy-cmd` option, so when you call either of them, nvm will be loaded and run with +default version. To enable it, you can add this snippet to your zshrc, before Oh My Zsh is sourced: + +```zsh +zstyle ':omz:plugins:nvm' lazy yes +``` + +Then, to define extra commands that will also trigger nvm load, you can use a similar syntax, adding as many +as you want: + +```zsh +zstyle ':omz:plugins:nvm' lazy-cmd eslint prettier typescript ... +``` + +#### `.nvmrc` autoload + +Note: _this option cannot be used at the same time as `lazy`. `autoload` will override it and load `nvm` at +startup._ + +If set, the plugin will automatically load a node version when if finds a +[`.nvmrc` file](https://github.com/nvm-sh/nvm#nvmrc) in the current working directory indicating which node +version to load. This can be done, similar as previous options, adding: + +```zsh +zstyle ':omz:plugins:nvm' autoload yes +zstyle ':omz:plugins:nvm' silent-autoload yes # optionally remove the output generated by NVM when autoloading +``` + +Note: _this will not remove regular `nvm` output_ diff --git a/plugins/nvm/nvm.plugin.zsh b/plugins/nvm/nvm.plugin.zsh index 630854a71..94b666175 100644 --- a/plugins/nvm/nvm.plugin.zsh +++ b/plugins/nvm/nvm.plugin.zsh @@ -4,57 +4,67 @@ if [[ -z "$NVM_DIR" ]]; then export NVM_DIR="$HOME/.nvm" elif [[ -d "${XDG_CONFIG_HOME:-$HOME/.config}/nvm" ]]; then export NVM_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nvm" + elif (( $+commands[brew] )); then + NVM_HOMEBREW="${NVM_HOMEBREW:-${HOMEBREW_PREFIX:-$(brew --prefix)}/opt/nvm}" + if [[ -d "$NVM_HOMEBREW" ]]; then + export NVM_DIR="$NVM_HOMEBREW" + fi fi fi # Don't try to load nvm if command already available # Note: nvm is a function so we need to use `which` -! which nvm &>/dev/null || return +which nvm &>/dev/null && return -if [[ -f "$NVM_DIR/nvm.sh" ]]; then - # Load nvm if it exists in $NVM_DIR - source "$NVM_DIR/nvm.sh" ${NVM_LAZY+"--no-use"} -elif (( $+commands[brew] )); then - # Otherwise try to load nvm installed via Homebrew - # User can set this if they have an unusual Homebrew setup - NVM_HOMEBREW="${NVM_HOMEBREW:-${HOMEBREW_PREFIX:-$(brew --prefix)}/opt/nvm}" - # Load nvm from Homebrew location if it exists - if [[ -f "$NVM_HOMEBREW/nvm.sh" ]]; then - source "$NVM_HOMEBREW/nvm.sh" ${NVM_LAZY+"--no-use"} - else - return - fi -else +if [[ -z "$NVM_DIR" ]] || [[ ! -f "$NVM_DIR/nvm.sh" ]]; then return fi -# Call nvm when first using node, npm or yarn -if (( $+NVM_LAZY )); then - function node npm yarn $NVM_LAZY_CMD { - unfunction node npm yarn $NVM_LAZY_CMD - nvm use default - command "$0" "$@" - } +if zstyle -t ':omz:plugins:nvm' lazy && \ + ! zstyle -t ':omz:plugins:nvm' autoload; then + # Call nvm when first using nvm, node, npm, pnpm, yarn or other commands in lazy-cmd + zstyle -a ':omz:plugins:nvm' lazy-cmd nvm_lazy_cmd + nvm_lazy_cmd=(nvm node npm npx pnpm yarn $nvm_lazy_cmd) # default values + eval " + function $nvm_lazy_cmd { + for func in $nvm_lazy_cmd; do + if (( \$+functions[\$func] )); then + unfunction \$func + fi + done + # Load nvm if it exists in \$NVM_DIR + [[ -f \"\$NVM_DIR/nvm.sh\" ]] && source \"\$NVM_DIR/nvm.sh\" + \"\$0\" \"\$@\" + } + " + unset nvm_lazy_cmd +else + source "$NVM_DIR/nvm.sh" fi # Autoload nvm when finding a .nvmrc file in the current directory # Adapted from: https://github.com/nvm-sh/nvm#zsh -if (( $+NVM_AUTOLOAD )); then - load-nvmrc() { +if zstyle -t ':omz:plugins:nvm' autoload; then + function load-nvmrc { local node_version="$(nvm version)" local nvmrc_path="$(nvm_find_nvmrc)" + local nvm_silent="" + zstyle -t ':omz:plugins:nvm' silent-autoload && nvm_silent="--silent" if [[ -n "$nvmrc_path" ]]; then - local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")") + local nvmrc_node_version=$(nvm version $(cat "$nvmrc_path" | tr -dc '[:print:]')) if [[ "$nvmrc_node_version" = "N/A" ]]; then nvm install elif [[ "$nvmrc_node_version" != "$node_version" ]]; then - nvm use + nvm use $nvm_silent fi elif [[ "$node_version" != "$(nvm version default)" ]]; then - echo "Reverting to nvm default version" - nvm use default + if [[ -z $nvm_silent ]]; then + echo "Reverting to nvm default version" + fi + + nvm use default $nvm_silent fi } @@ -76,4 +86,4 @@ for nvm_completion in "$NVM_DIR/bash_completion" "$NVM_HOMEBREW/etc/bash_complet fi done -unset NVM_HOMEBREW NVM_LAZY NVM_AUTOLOAD nvm_completion +unset NVM_HOMEBREW nvm_completion diff --git a/plugins/per-directory-history/README.md b/plugins/per-directory-history/README.md index 69854aa38..11150b059 100644 --- a/plugins/per-directory-history/README.md +++ b/plugins/per-directory-history/README.md @@ -34,6 +34,8 @@ toggle set the `PER_DIRECTORY_HISTORY_TOGGLE` environment variable. and global histories. * `PER_DIRECTORY_HISTORY_TOGGLE` is the key binding used to run the toggle-history function above (default `^G`) +* `PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE` is a variable which toggles whether + the current mode is printed to the screen following a mode change (default `true`) ## History diff --git a/plugins/per-directory-history/per-directory-history.zsh b/plugins/per-directory-history/per-directory-history.zsh index 7cd673cdb..b33e0b5dd 100644 --- a/plugins/per-directory-history/per-directory-history.zsh +++ b/plugins/per-directory-history/per-directory-history.zsh @@ -59,6 +59,7 @@ [[ -z $HISTORY_BASE ]] && HISTORY_BASE="$HOME/.directory_history" [[ -z $HISTORY_START_WITH_GLOBAL ]] && HISTORY_START_WITH_GLOBAL=false [[ -z $PER_DIRECTORY_HISTORY_TOGGLE ]] && PER_DIRECTORY_HISTORY_TOGGLE='^G' +[[ -z $PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE ]] && PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE=true #------------------------------------------------------------------------------- # toggle global/directory history used for searching - ctrl-G by default @@ -68,19 +69,22 @@ function per-directory-history-toggle-history() { if [[ $_per_directory_history_is_global == true ]]; then _per-directory-history-set-directory-history _per_directory_history_is_global=false - print -n "\nusing local history" + if [[ $PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE == true ]]; then + zle -M "using local history" + fi else _per-directory-history-set-global-history _per_directory_history_is_global=true - print -n "\nusing global history" + if [[ $PER_DIRECTORY_HISTORY_PRINT_MODE_CHANGE == true ]]; then + zle -M "using global history" + fi fi - zle .push-line - zle .accept-line } autoload per-directory-history-toggle-history zle -N per-directory-history-toggle-history bindkey $PER_DIRECTORY_HISTORY_TOGGLE per-directory-history-toggle-history +bindkey -M vicmd $PER_DIRECTORY_HISTORY_TOGGLE per-directory-history-toggle-history #------------------------------------------------------------------------------- # implementation details diff --git a/plugins/perms/README.md b/plugins/perms/README.md index ae7a36b9d..ae10fa659 100644 --- a/plugins/perms/README.md +++ b/plugins/perms/README.md @@ -10,6 +10,16 @@ plugins=(... perms) ## Usage -* `set755` recursively sets all given directories (default to .) to octal 755. -* `set644` recursively sets all given files (default to .) to octal 644. -* `fixperms` is a wrapper around `set755` and `set644` applied to a specified directory or the current directory otherwise. It also prompts prior to execution unlike the other two aliases. +> **CAUTION:** these functions are harmful if you don't know what they do. + +- `set755`: sets the permission to octal 755 for all given directories and their child directories (by default, starting from the current directory). + +- `set644`: sets the permission to octal 644 for all files of the given directory (by default, the current directory), recursively. It will only affect regular files (no symlinks). + +- `resetperms` is a wrapper around `set755` and `set644` applied to a specified directory or the current directory otherwise. + It will set the permissions to 755 for directories, and 644 for files. + +## Reference + +- octal 644: _read and write_ for the owner, _read_ for the group and others users. +- octal 755: _read, write and execute_ permissions for the owner, and _read and execute_ for the group and others users. diff --git a/plugins/perms/perms.plugin.zsh b/plugins/perms/perms.plugin.zsh index 1a7472c1c..353b58411 100644 --- a/plugins/perms/perms.plugin.zsh +++ b/plugins/perms/perms.plugin.zsh @@ -6,25 +6,25 @@ ### Aliases # Set all files' permissions to 644 recursively in a directory -set644() { +function set644 { find "${@:-.}" -type f ! -perm 644 -print0 | xargs -0 chmod 644 } # Set all directories' permissions to 755 recursively in a directory -set755() { +function set755 { find "${@:-.}" -type d ! -perm 755 -print0 | xargs -0 chmod 755 } ### Functions -# fixperms - fix permissions on files and directories, with confirmation +# resetperms - fix permissions on files and directories, with confirmation # Returns 0 on success, nonzero if any errors occurred -fixperms () { +function resetperms { local opts confirm target exit_status chmod_opts use_slow_mode zparseopts -E -D -a opts -help -slow v+=chmod_opts if [[ $# > 1 || -n "${opts[(r)--help]}" ]]; then cat </dev/null | grep -q GNU || xargs="xargs" - pip list --outdated --format freeze | cut -d= -f1 | ${=xargs} pip install --upgrade + pip list --outdated | awk 'NR > 2 { print $1 }' | ${=xargs} pip install --upgrade } -# Uninstalled all installed packages +# Uninstall all installed packages function pipunall { # non-GNU xargs does not support nor need `--no-run-if-empty` local xargs="xargs --no-run-if-empty" xargs --version 2>/dev/null | grep -q GNU || xargs="xargs" pip list --format freeze | cut -d= -f1 | ${=xargs} pip uninstall } + +# Install from GitHub repository +function pipig { + pip install "git+https://github.com/$1.git" +} +compdef _pip pipig + +# Install from GitHub branch +function pipigb { + pip install "git+https://github.com/$1.git@$2" +} +compdef _pip pipigb + +# Install from GitHub pull request +function pipigp { + pip install "git+https://github.com/$1.git@refs/pull/$2/head" +} +compdef _pip pipigp diff --git a/plugins/pipenv/README.md b/plugins/pipenv/README.md index ab1c1e442..e78ef0e3b 100644 --- a/plugins/pipenv/README.md +++ b/plugins/pipenv/README.md @@ -1,6 +1,7 @@ # Pipenv ## Installation + In your `.zshrc` file, add `pipenv` to the plugins section ``` @@ -8,7 +9,9 @@ plugins=(... pipenv ...) ``` ## Features -This plugin provides some features to simplify the use of Pipenv while working on ZSH. + +This plugin provides some features to simplify the use of Pipenv while working on ZSH. + - Adds completion for pipenv - Auto activates and deactivates pipenv shell - Adds short aliases for common pipenv commands @@ -23,6 +26,17 @@ This plugin provides some features to simplify the use of Pipenv while working o - `psh` is aliased to `pipenv shell` - `psy` is aliased to `pipenv sync` - `pu` is aliased to `pipenv uninstall` + - `pupd` is aliased to `pipenv update` - `pwh` is aliased to `pipenv --where` - `pvenv` is aliased to `pipenv --venv` - `ppy` is aliased to `pipenv --py` + +## Configuration + +### Shell activation + +If you want to disable the shell activation and deactivation feature, add the following style to your `.zshrc` before sourcing `oh-my-zsh.sh`: + +```zsh +zstyle ':omz:plugins:pipenv' auto-shell no +``` diff --git a/plugins/pipenv/pipenv.plugin.zsh b/plugins/pipenv/pipenv.plugin.zsh index 4be61a920..f81c266a4 100644 --- a/plugins/pipenv/pipenv.plugin.zsh +++ b/plugins/pipenv/pipenv.plugin.zsh @@ -1,31 +1,41 @@ -# Pipenv completion -_pipenv() { - eval $(env COMMANDLINE="${words[1,$CURRENT]}" _PIPENV_COMPLETE=complete-zsh pipenv) -} -compdef _pipenv pipenv +if (( ! $+commands[pipenv] )); then + return +fi -# Automatic pipenv shell activation/deactivation -_togglePipenvShell() { - # deactivate shell if Pipfile doesn't exist and not in a subdir - if [[ ! -f "$PWD/Pipfile" ]]; then - if [[ "$PIPENV_ACTIVE" == 1 ]]; then - if [[ "$PWD" != "$pipfile_dir"* ]]; then - exit +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `pipenv`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_pipenv" ]]; then + typeset -g -A _comps + autoload -Uz _pipenv + _comps[pipenv]=_pipenv +fi + +_PIPENV_COMPLETE=zsh_source pipenv >| "$ZSH_CACHE_DIR/completions/_pipenv" &| + +if zstyle -T ':omz:plugins:pipenv' auto-shell; then + # Automatic pipenv shell activation/deactivation + _togglePipenvShell() { + # deactivate shell if Pipfile doesn't exist and not in a subdir + if [[ ! -f "$PWD/Pipfile" ]]; then + if [[ "$PIPENV_ACTIVE" == 1 ]]; then + if [[ "$PWD" != "$pipfile_dir"* ]]; then + exit + fi fi fi - fi - # activate the shell if Pipfile exists - if [[ "$PIPENV_ACTIVE" != 1 ]]; then - if [[ -f "$PWD/Pipfile" ]]; then - export pipfile_dir="$PWD" - pipenv shell + # activate the shell if Pipfile exists + if [[ "$PIPENV_ACTIVE" != 1 ]]; then + if [[ -f "$PWD/Pipfile" ]]; then + export pipfile_dir="$PWD" + pipenv shell + fi fi - fi -} -autoload -U add-zsh-hook -add-zsh-hook chpwd _togglePipenvShell -_togglePipenvShell + } + autoload -U add-zsh-hook + add-zsh-hook chpwd _togglePipenvShell + _togglePipenvShell +fi # Aliases alias pch="pipenv check" @@ -39,6 +49,7 @@ alias prun="pipenv run" alias psh="pipenv shell" alias psy="pipenv sync" alias pu="pipenv uninstall" +alias pupd="pipenv update" alias pwh="pipenv --where" alias pvenv="pipenv --venv" alias ppy="pipenv --py" diff --git a/plugins/pm2/_pm2 b/plugins/pm2/_pm2 index 86412aef1..faa6a3404 100644 --- a/plugins/pm2/_pm2 +++ b/plugins/pm2/_pm2 @@ -118,7 +118,7 @@ start_options=( ) logs_options=( '--json[json log output]' - '--format[formated log output]' + '--format[formatted log output]' '--raw[raw output]' '--err[only shows error output]' '--out[only shows standard output]' diff --git a/plugins/pod/_pod b/plugins/pod/_pod index 80d23daad..d560129db 100644 --- a/plugins/pod/_pod +++ b/plugins/pod/_pod @@ -6,7 +6,7 @@ # ----------------------------------------------------------------------------- # FILE: _pod -# DESCRIPTION: Cocoapods (0.33.1) autocomplete plugin for Oh-My-Zsh +# DESCRIPTION: CocoaPods (0.33.1) autocomplete plugin for Oh-My-Zsh # https://cocoapods.org # Generated with `pod --completion-script # AUTHOR: Alexandre Joly (alexandre.joly@mekanics.ch) diff --git a/plugins/podman/README.md b/plugins/podman/README.md new file mode 100644 index 000000000..99daa28cd --- /dev/null +++ b/plugins/podman/README.md @@ -0,0 +1,47 @@ +# Podman plugin + +This plugin adds auto-completion and aliases for [podman](https://podman.io/). + +To use it add `podman` to the plugins array in your zshrc file. + +```zsh +plugins=(... podman) +``` + +## Aliases + +| Alias | Command | Description | +| :------ | :-------------------------------------------- | :--------------------------------------------------------------------------------------- | +| pbl | `podman build` | Build an image from a Dockerfile | +| pcin | `podman container inspect` | Display detailed information on one or more containers | +| pcls | `podman container ls` | List all the running podman containers | +| pclsa | `podman container ls --all` | List all running and stopped containers | +| pib | `podman image build` | Build an image from a Dockerfile (same as podman build) | +| pii | `podman image inspect` | Display detailed information on one or more images | +| pils | `podman image ls` | List podman images | +| pipu | `podman image push` | Push an image or repository to a remote registry | +| pirm | `podman image rm` | Remove one or more images | +| pit | `podman image tag` | Add a name and tag to a particular image | +| plo | `podman container logs` | Fetch the logs of a podman container | +| pnc | `podman network create` | Create a new network | +| pncn | `podman network connect` | Connect a container to a network | +| pndcn | `podman network disconnect` | Disconnect a container from a network | +| pni | `podman network inspect` | Return information about one or more networks | +| pnls | `podman network ls` | List all networks the engine daemon knows about, including those spanning multiple hosts | +| pnrm | `podman network rm` | Remove one or more networks | +| ppo | `podman container port` | List port mappings or a specific mapping for the container | +| ppu | `podman pull` | Pull an image or a repository from a registry | +| pr | `podman container run` | Create a new container and start it using the specified command | +| prit | `podman container run --interactive --tty` | Create a new container and start it in an interactive shell | +| prm | `podman container rm` | Remove the specified container(s) | +| prm! | `podman container rm --force` | Force the removal of a running container (uses SIGKILL) | +| pst | `podman container start` | Start one or more stopped containers | +| prs | `podman container restart` | Restart one or more containers | +| psta | `podman stop $(podman ps -q)` | Stop all running containers | +| pstp | `podman container stop` | Stop one or more running containers | +| ptop | `podman top` | Display the running processes of a container | +| pvi | `podman volume inspect` | Display detailed information about one or more volumes | +| pvls | `podman volume ls` | List all the volumes known to podman | +| pvprune | `podman volume prune` | Cleanup dangling volumes | +| pxc | `podman container exec` | Run a new command in a running container | +| pxcit | `podman container exec --interactive --tty` | Run a new command in a running container in an interactive shell | diff --git a/plugins/podman/podman.plugin.zsh b/plugins/podman/podman.plugin.zsh new file mode 100644 index 000000000..97cf92b2a --- /dev/null +++ b/plugins/podman/podman.plugin.zsh @@ -0,0 +1,47 @@ +if (( ! $+commands[podman] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `podman`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_podman" ]]; then + typeset -g -A _comps + autoload -Uz _podman + _comps[podman]=_podman +fi + +podman completion zsh 2> /dev/null >| "$ZSH_CACHE_DIR/completions/_podman" &| + +alias pbl='podman build' +alias pcin='podman container inspect' +alias pcls='podman container ls' +alias pclsa='podman container ls --all' +alias pib='podman image build' +alias pii='podman image inspect' +alias pils='podman image ls' +alias pipu='podman image push' +alias pirm='podman image rm' +alias pit='podman image tag' +alias plo='podman container logs' +alias pnc='podman network create' +alias pncn='podman network connect' +alias pndcn='podman network disconnect' +alias pni='podman network inspect' +alias pnls='podman network ls' +alias pnrm='podman network rm' +alias ppo='podman container port' +alias ppu='podman pull' +alias pr='podman container run' +alias prit='podman container run --interactive --tty' +alias prm='podman container rm' +alias 'prm!'='podman container rm --force' +alias pst='podman container start' +alias prs='podman container restart' +alias psta='podman stop $(podman ps --quiet)' +alias pstp='podman container stop' +alias ptop='podman top' +alias pvi='podman volume inspect' +alias pvls='podman volume ls' +alias pvprune='podman volume prune' +alias pxc='podman container exec' +alias pxcit='podman container exec --interactive --tty' diff --git a/plugins/poetry-env/README.md b/plugins/poetry-env/README.md new file mode 100644 index 000000000..a7d16563e --- /dev/null +++ b/plugins/poetry-env/README.md @@ -0,0 +1,10 @@ +# Poetry Environment Plugin + +This plugin automatically changes poetry environment when you cd into or out of the project directory. +Note: Script looks for pyproject.toml file to determine poetry if its a poetry environment + +To use it, add `poetry-env` to the plugins array in your zshrc file: + +```zsh +plugins=(... poetry-env) +``` diff --git a/plugins/poetry-env/poetry-env.plugin.zsh b/plugins/poetry-env/poetry-env.plugin.zsh new file mode 100644 index 000000000..86e5fad4e --- /dev/null +++ b/plugins/poetry-env/poetry-env.plugin.zsh @@ -0,0 +1,27 @@ +# Automatic poetry environment activation/deactivation +_togglePoetryShell() { + # deactivate environment if pyproject.toml doesn't exist and not in a subdir + if [[ ! -f "$PWD/pyproject.toml" ]] ; then + if [[ "$poetry_active" == 1 ]]; then + if [[ "$PWD" != "$poetry_dir"* ]]; then + export poetry_active=0 + deactivate + return + fi + fi + fi + + # activate the environment if pyproject.toml exists + if [[ "$poetry_active" != 1 ]]; then + if [[ -f "$PWD/pyproject.toml" ]]; then + if grep -q 'tool.poetry' "$PWD/pyproject.toml"; then + export poetry_active=1 + export poetry_dir="$PWD" + source "$(poetry env info --path)/bin/activate" + fi + fi + fi +} +autoload -U add-zsh-hook +add-zsh-hook chpwd _togglePoetryShell +_togglePoetryShell diff --git a/plugins/postgres/README.md b/plugins/postgres/README.md index 59445f31c..3f59a8fe4 100644 --- a/plugins/postgres/README.md +++ b/plugins/postgres/README.md @@ -19,4 +19,4 @@ plugins=(... postgres) | stoppost | `pg_ctl -D /usr/local/var/postgres stop -s -m fast` | Stop postgres server | | restartpost | `stoppost && sleep 1 && startpost` | Restart (calls stop, then start) | | reloadpost | `pg_ctl reload -D /usr/local/var/postgres -s` | Reload postgres configuration (some setting require restart)| -| statuspost | `pg_ctl status -D /usr/local/var/postgres -s` | Check startus of postgres server (running, stopped) | +| statuspost | `pg_ctl status -D /usr/local/var/postgres -s` | Check status of postgres server (running, stopped) | diff --git a/plugins/pre-commit/README.md b/plugins/pre-commit/README.md new file mode 100644 index 000000000..e6d80d369 --- /dev/null +++ b/plugins/pre-commit/README.md @@ -0,0 +1,19 @@ +# Pre-commit plugin + +This plugin adds aliases for common commands of [pre-commit](https://pre-commit.com/). + +To use this plugin, add it to the plugins array in your zshrc file: + +```zsh +plugins=(... pre-commit) +``` + +## Aliases + +| Alias | Command | Description | +| ------- | -------------------------------------- | ------------------------------------------------------ | +| prc | `pre-commit` | The `pre-commit` command | +| prcau | `pre-commit autoupdate` | Update hooks automatically | +| prcr | `pre-commit run` | The `pre-commit run` command | +| prcra | `pre-commit run --all-files` | Run pre-commit hooks on all files | +| prcrf | `pre-commit run --files` | Run pre-commit hooks on a given list of files | diff --git a/plugins/pre-commit/pre-commit.plugin.zsh b/plugins/pre-commit/pre-commit.plugin.zsh new file mode 100644 index 000000000..c3d0c6290 --- /dev/null +++ b/plugins/pre-commit/pre-commit.plugin.zsh @@ -0,0 +1,8 @@ +# Aliases for pre-commit +alias prc='pre-commit' + +alias prcau='pre-commit autoupdate' + +alias prcr='pre-commit run' +alias prcra='pre-commit run --all-files' +alias prcrf='pre-commit run --files' diff --git a/plugins/pyenv/README.md b/plugins/pyenv/README.md index b9ee937b7..f1ca3d288 100644 --- a/plugins/pyenv/README.md +++ b/plugins/pyenv/README.md @@ -10,6 +10,14 @@ To use it, add `pyenv` to the plugins array in your zshrc file: plugins=(... pyenv) ``` +If you receive a `Found pyenv, but it is badly configured.` error on startup, you may need to ensure that `pyenv` is initialized before the oh-my-zsh pyenv plugin is loaded. This can be achived by adding the following earlier in the `.zshrc` file than the `plugins=(...)` line: + +```zsh +export PYENV_ROOT="$HOME/.pyenv" +export PATH="$PYENV_ROOT/bin:$PATH" +eval "$(pyenv init --path)" +``` + ## Settings - `ZSH_PYENV_QUIET`: if set to `true`, the plugin will not print any messages if it diff --git a/plugins/pyenv/pyenv.plugin.zsh b/plugins/pyenv/pyenv.plugin.zsh index 7fbd1589e..48c8ffaf5 100644 --- a/plugins/pyenv/pyenv.plugin.zsh +++ b/plugins/pyenv/pyenv.plugin.zsh @@ -78,7 +78,7 @@ if [[ $FOUND_PYENV -eq 1 ]]; then eval "$(pyenv init - --no-rehash zsh)" # If pyenv-virtualenv exists, load it - if [[ "$(pyenv commands)" =~ "virtualenv-init" && "$ZSH_PYENV_VIRTUALENV" != false ]]; then + if [[ "$ZSH_PYENV_VIRTUALENV" != false && "$(pyenv commands)" =~ "virtualenv-init" ]]; then eval "$(pyenv virtualenv-init - zsh)" fi diff --git a/plugins/python/README.md b/plugins/python/README.md index 97c1a34ee..7bf1b34ac 100644 --- a/plugins/python/README.md +++ b/plugins/python/README.md @@ -12,7 +12,7 @@ plugins=(... python) | Command | Description | | ---------------- | -------------------------------------------------------------------------------------- | -| `py` | Runs `python3` | +| `py` | Runs `python3`. Only set if `py` is not installed. | | `ipython` | Runs the appropriate `ipython` version according to the activated virtualenv | | `pyfind` | Finds .py files recursively in the current directory | | `pyclean [dirs]` | Deletes byte-code and cache files from a list of directories or the current one | diff --git a/plugins/python/python.plugin.zsh b/plugins/python/python.plugin.zsh index 2fbb59577..3d7ca55c9 100644 --- a/plugins/python/python.plugin.zsh +++ b/plugins/python/python.plugin.zsh @@ -1,5 +1,5 @@ -# python command -alias py='python3' +# set python command if 'py' not installed +builtin which py > /dev/null || alias py='python3' # Find python file alias pyfind='find . -name "*.py"' diff --git a/plugins/qodana/README.md b/plugins/qodana/README.md new file mode 100644 index 000000000..0b68bdecf --- /dev/null +++ b/plugins/qodana/README.md @@ -0,0 +1,20 @@ +# JetBrains Qodana CLI plugin + +This plugin adds completion for the [JetBrains Qodana CLI](https://github.com/JetBrains/qodana-cli). + +To use it, add `qodana` to the plugins array in your zshrc file: + +```zsh +plugins=(... qodana) +``` + +This plugin does not add any aliases. + +## Cache + +This plugin caches the completion script and is automatically updated when the +plugin is loaded, which is usually when you start up a new terminal emulator. + +The cache is stored at: + +- `$ZSH_CACHE_DIR/completions/_qodana` completions script diff --git a/plugins/qodana/qodana.plugin.zsh b/plugins/qodana/qodana.plugin.zsh new file mode 100644 index 000000000..2b92a8051 --- /dev/null +++ b/plugins/qodana/qodana.plugin.zsh @@ -0,0 +1,14 @@ +# Autocompletion for the JetBrains Qodana CLI (qodana). +if (( ! $+commands[qodana] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `qodana`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_qodana" ]]; then + typeset -g -A _comps + autoload -Uz _qodana + _comps[qodana]=_qodana +fi + +qodana completion zsh >| "$ZSH_CACHE_DIR/completions/_qodana" &| diff --git a/plugins/qrcode/README.md b/plugins/qrcode/README.md new file mode 100644 index 000000000..442838947 --- /dev/null +++ b/plugins/qrcode/README.md @@ -0,0 +1,8 @@ +# QRCode plugin + +Generate a QR Code from the command line. Uses [QRcode.show](https://qrcode.show) via curl. + +alias | command +--------------- | -------- +`qrcode [text]` | `curl -d "text" qrcode.show` +`qrsvg [text]` | `curl -d "text" qrcode.show -H "Accept: image/svg+xml"` diff --git a/plugins/qrcode/qrcode.plugin.zsh b/plugins/qrcode/qrcode.plugin.zsh new file mode 100644 index 000000000..d757e135e --- /dev/null +++ b/plugins/qrcode/qrcode.plugin.zsh @@ -0,0 +1,17 @@ +# Imported and improved from https://qrcode.show/, section SHELL FUNCTIONS + +_qrcode_show_message() { + echo "Type or paste your text, add a new blank line, and press ^d" +} + +qrcode () { + local input="$*" + [ -z "$input" ] && _qrcode_show_message && local input="@/dev/stdin" + curl -d "$input" https://qrcode.show +} + +qrsvg () { + local input="$*" + [ -z "$input" ] && _qrcode_show_message && local input="@/dev/stdin" + curl -d "$input" https://qrcode.show -H "Accept: image/svg+xml" +} diff --git a/plugins/rails/README.md b/plugins/rails/README.md index fa66750f0..c0c37ff3d 100644 --- a/plugins/rails/README.md +++ b/plugins/rails/README.md @@ -40,13 +40,17 @@ plugins=(... rails) | `rn` | `rails notes` | Search for notes (`FIXME`, `TODO`) in code comments | | `rp` | `rails plugin` | Run a Rails plugin command | | `rr` | `rails routes` | List all defined routes | -| `rrg` | `rails routes \| grep` | List and filter the defined routes | +| `rrc` | `rails routes --controller` | List and filter routes mapped to specific controller | +| `rre` | `rails routes --expanded` | List all defined routes in expanded table mode | +| `rrg` | `rails routes --grep` | List and filter the defined routes | +| `rru` | `rails routes --unused` | List unused routes | | `rs` | `rails server` | Launch a web server | | `rsb` | `rails server --bind` | Launch a web server binding it to a specific IP | | `rsd` | `rails server --debugger` | Launch a web server with debugger | | `rsp` | `rails server --port` | Launch a web server and specify the listening port | | `rsts` | `rails stats` | Print code statistics | | `rt` | `rails test` | Run Rails tests | +| `rta` | `rails test:all` | Runs all Rails tests, including system tests | | `ru` | `rails runner` | Run Ruby code in the context of Rails | ### Foreman diff --git a/plugins/rails/_rails b/plugins/rails/_rails index 6dc85d458..ac90d45cc 100644 --- a/plugins/rails/_rails +++ b/plugins/rails/_rails @@ -1,6 +1,6 @@ #compdef rails # ------------------------------------------------------------------------------ -# Copyright (c) 2016 Github zsh-users - http://github.com/zsh-users +# Copyright (c) 2016 GitHub zsh-users - http://github.com/zsh-users # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/plugins/rails/rails.plugin.zsh b/plugins/rails/rails.plugin.zsh index b11cbb5c7..75dd9b0c6 100644 --- a/plugins/rails/rails.plugin.zsh +++ b/plugins/rails/rails.plugin.zsh @@ -68,13 +68,17 @@ alias rmd='rails middleware' alias rn='rails notes' alias rp='rails plugin' alias rr='rails routes' -alias rrg='rails routes | grep' +alias rrc='rails routes --controller' +alias rre='rails routes --expanded' +alias rrg='rails routes --grep' +alias rru='rails routes --unused' alias rs='rails server' alias rsb='rails server --bind' alias rsd='rails server --debugger' alias rsp='rails server --port' alias rsts='rails stats' alias rt='rails test' +alias rta='rails test:all' alias ru='rails runner' # Foreman aliases diff --git a/plugins/rake-fast/rake-fast.plugin.zsh b/plugins/rake-fast/rake-fast.plugin.zsh index 19dab154b..082f02f29 100644 --- a/plugins/rake-fast/rake-fast.plugin.zsh +++ b/plugins/rake-fast/rake-fast.plugin.zsh @@ -1,5 +1,28 @@ +# The version of the format of .rake_tasks. If the output of _rake_generate +# changes, incrementing this number will force it to regenerate +_rake_tasks_version=2 + _rake_does_task_list_need_generating () { - [[ ! -f .rake_tasks ]] || [[ Rakefile -nt .rake_tasks ]] || { _is_rails_app && _tasks_changed } + _rake_tasks_missing || _rake_tasks_version_changed || _rakefile_has_changes || { _is_rails_app && _tasks_changed } +} + +_rake_tasks_missing () { + [[ ! -f .rake_tasks ]] +} + +_rake_tasks_version_changed () { + local -a file_version + file_version=`head -n 1 .rake_tasks | sed "s/^version\://"` + + if ! [[ $file_version =~ '^[0-9]*$' ]]; then + return true + fi + + [[ $file_version -ne $_rake_tasks_version ]] +} + +_rakefile_has_changes () { + [[ Rakefile -nt .rake_tasks ]] } _is_rails_app () { @@ -20,7 +43,17 @@ _tasks_changed () { } _rake_generate () { - rake --silent --tasks | cut -d " " -f 2 | sed 's/\[.*\]//g' > .rake_tasks + local rake_tasks_content="version:$_rake_tasks_version\n" + rake_tasks_content+=$(rake --silent --tasks --all \ + | sed "s/^rake //" | sed "s/\:/\\\:/g" \ + | sed "s/\[[^]]*\]//g" \ + | sed "s/ *# /\:/" \ + | sed "s/\:$//") + + local rake_tasks_file="$(mktemp -t .rake_tasks.XXXXXX)" + echo $rake_tasks_content > $rake_tasks_file + + mv $rake_tasks_file .rake_tasks } _rake () { @@ -29,7 +62,10 @@ _rake () { echo "\nGenerating .rake_tasks..." >&2 _rake_generate fi - compadd $(cat .rake_tasks) + local -a rake_options + rake_options=("${(@f)$(cat .rake_tasks)}") + shift rake_options + _describe 'rake tasks' rake_options fi } compdef _rake rake diff --git a/plugins/react-native/README.md b/plugins/react-native/README.md index d0a53b8d7..39eed6c68 100644 --- a/plugins/react-native/README.md +++ b/plugins/react-native/README.md @@ -11,66 +11,82 @@ plugins=(... react-native) ## Aliases -| Alias | React Native command | -| :------------ | :------------------------------------------------- | -| **rn** | `react-native` | -| **rns** | `react-native start` | -| **rnlink** | `react-native link` | -| _Logging_ | | -| **rnland** | `react-native log-android` | -| **rnlios** | `react-native log-ios` | -| _App Testing_ | | -| **rnand** | `react-native run-android` | -| **rnios** | `react-native run-ios` | -| _iPhone_ | | -| **rnios4s** | `react-native run-ios --simulator "iPhone 4s"` | -| **rnios5** | `react-native run-ios --simulator "iPhone 5"` | -| **rnios5s** | `react-native run-ios --simulator "iPhone 5s"` | -| **rnios6** | `react-native run-ios --simulator "iPhone 6"` | -| **rnios6s** | `react-native run-ios --simulator "iPhone 6s"` | -| **rnios6p** | `react-native run-ios --simulator "iPhone 6 Plus"` | -| **rnios6sp** | `react-native run-ios --simulator "iPhone 6s Plus"` | -| **rnios7** | `react-native run-ios --simulator "iPhone 7"` | -| **rnios7p** | `react-native run-ios --simulator "iPhone 7 Plus"` | -| **rnios8** | `react-native run-ios --simulator "iPhone 8"` | -| **rnios8p** | `react-native run-ios --simulator "iPhone 8 Plus"` | -| **rniosse** | `react-native run-ios --simulator "iPhone SE"` | -| **rniosx** | `react-native run-ios --simulator "iPhone X"` | -| **rniosxs** | `react-native run-ios --simulator "iPhone Xs"` | -| **rniosxsm** | `react-native run-ios --simulator "iPhone Xs Max"` | -| **rniosxr** | `react-native run-ios --simulator "iPhone Xʀ"` | -| **rnios11** | `react-native run-ios --simulator "iPhone 11"` | -| **rnios11p** | `react-native run-ios --simulator "iPhone 11 Pro"` | -| **rnios11pm** | `react-native run-ios --simulator "iPhone 11 Pro Max"` | -| _iPad_ | | -| **rnipad2** | `react-native run-ios --simulator "iPad 2"` | -| **rnipad5** | `react-native run-ios --simulator "iPad (5th generation)"` | -| **rnipad6** | `react-native run-ios --simulator "iPad (6th generation)"` | -| **rnipadr** | `react-native run-ios --simulator "iPad Retina"` | -| **rnipada** | `react-native run-ios --simulator "iPad Air"` | -| **rnipada2** | `react-native run-ios --simulator "iPad Air 2"` | -| **rnipada3** | `react-native run-ios --simulator "iPad Air (3rd generation)"` | -| **rnipadm2** | `react-native run-ios --simulator "iPad mini 2"` | -| **rnipadm3** | `react-native run-ios --simulator "iPad mini 3"` | -| **rnipadm4** | `react-native run-ios --simulator "iPad mini 4"` | -| **rnipadm5** | `react-native run-ios --simulator "iPad mini (5th generation)"` | -| **rnipadp9** | `react-native run-ios --simulator "iPad Pro (9.7-inch)"` | -| **rnipadp12** | `react-native run-ios --simulator "iPad Pro (12.9-inch)"` | -| **rnipadp122** | `react-native run-ios --simulator "iPad Pro (12.9-inch) (2nd generation)"` | -| **rnipadp10** | `react-native run-ios --simulator "iPad Pro (10.5-inch)"` | -| **rnipad11** | `react-native run-ios --simulator "iPad Pro (11-inch)"` | -| **rnipad123** | `react-native run-ios --simulator "iPad Pro (12.9-inch) (3rd generation)"` | -| _Apple TV_ | | -| **rnatv** | `react-native run-ios --simulator "Apple TV"` | -| **rnatv4k** | `react-native run-ios --simulator "Apple TV 4K"` | -| **rnatv4k1080**| `react-native run-ios --simulator "Apple TV 4K (at 1080p)"` | -| **rnipad123** | `react-native run-ios --simulator "iPad Pro (12.9-inch) (3rd generation)"` | -| _Apple Watch_ | | -| **rnaw38** | `react-native run-ios --simulator "Apple Watch - 38mm"` | -| **rnaw42** | `react-native run-ios --simulator "Apple Watch - 42mm"` | -| **rnaws238** | `react-native run-ios --simulator "Apple Watch Series 2 - 38mm"` | -| **rnaws242** | `react-native run-ios --simulator "Apple Watch Series 2 - 42mm"` | -| **rnaws338** | `react-native run-ios --simulator "Apple Watch Series 3 - 38mm"` | -| **rnaws342** | `react-native run-ios --simulator "Apple Watch Series 3 - 42mm"` | -| **rnaws440** | `react-native run-ios --simulator "Apple Watch Series 4 - 40mm"` | -| **rnaws444** | `react-native run-ios --simulator "Apple Watch Series 4 - 44mm"` | +| Alias | React Native command | +| :-------------- | :------------------------------------------------------------------------- | +| **rn** | `react-native` | +| **rns** | `react-native start` | +| **rnlink** | `react-native link` | +| _Logging_ | | +| **rnland** | `react-native log-android` | +| **rnlios** | `react-native log-ios` | +| _App Testing_ | | +| **rnand** | `react-native run-android` | +| **rnios** | `react-native run-ios` | +| _iPhone_ | | +| **rnios4s** | `react-native run-ios --simulator "iPhone 4s"` | +| **rnios5** | `react-native run-ios --simulator "iPhone 5"` | +| **rnios5s** | `react-native run-ios --simulator "iPhone 5s"` | +| **rnios6** | `react-native run-ios --simulator "iPhone 6"` | +| **rnios6s** | `react-native run-ios --simulator "iPhone 6s"` | +| **rnios6p** | `react-native run-ios --simulator "iPhone 6 Plus"` | +| **rnios6sp** | `react-native run-ios --simulator "iPhone 6s Plus"` | +| **rnios7** | `react-native run-ios --simulator "iPhone 7"` | +| **rnios7p** | `react-native run-ios --simulator "iPhone 7 Plus"` | +| **rnios8** | `react-native run-ios --simulator "iPhone 8"` | +| **rnios8p** | `react-native run-ios --simulator "iPhone 8 Plus"` | +| **rniosse** | `react-native run-ios --simulator "iPhone SE"` | +| **rniosx** | `react-native run-ios --simulator "iPhone X"` | +| **rniosxs** | `react-native run-ios --simulator "iPhone Xs"` | +| **rniosxsm** | `react-native run-ios --simulator "iPhone Xs Max"` | +| **rniosxr** | `react-native run-ios --simulator "iPhone Xʀ"` | +| **rnios11** | `react-native run-ios --simulator "iPhone 11"` | +| **rnios11p** | `react-native run-ios --simulator "iPhone 11 Pro"` | +| **rnios11pm** | `react-native run-ios --simulator "iPhone 11 Pro Max"` | +| **rnios12** | `react-native run-ios --simulator "iPhone 12"` | +| **rnios12m** | `react-native run-ios --simulator "iPhone 12 mini"` | +| **rnios12p** | `react-native run-ios --simulator "iPhone 12 Pro"` | +| **rnios12pm** | `react-native run-ios --simulator "iPhone 12 Pro Max"` | +| **rnios13** | `react-native run-ios --simulator "iPhone 13"` | +| **rnios13m** | `react-native run-ios --simulator "iPhone 13 mini"` | +| **rnios13p** | `react-native run-ios --simulator "iPhone 13 Pro"` | +| **rnios13pm** | `react-native run-ios --simulator "iPhone 13 Pro Max"` | +| **rnios14** | `react-native run-ios --simulator "iPhone 14"` | +| **rnios14pl** | `react-native run-ios --simulator "iPhone 14 Plus"` | +| **rnios14p** | `react-native run-ios --simulator "iPhone 14 Pro"` | +| **rnios14pm** | `react-native run-ios --simulator "iPhone 14 Pro Max"` | +| **rnios15** | `react-native run-ios --simulator "iPhone 15"` | +| **rnios15pl** | `react-native run-ios --simulator "iPhone 15 Plus"` | +| **rnios15p** | `react-native run-ios --simulator "iPhone 15 Pro"` | +| **rnios15pm** | `react-native run-ios --simulator "iPhone 15 Pro Max"` | +| _iPad_ | | +| **rnipad2** | `react-native run-ios --simulator "iPad 2"` | +| **rnipad5** | `react-native run-ios --simulator "iPad (5th generation)"` | +| **rnipad6** | `react-native run-ios --simulator "iPad (6th generation)"` | +| **rnipadr** | `react-native run-ios --simulator "iPad Retina"` | +| **rnipada** | `react-native run-ios --simulator "iPad Air"` | +| **rnipada2** | `react-native run-ios --simulator "iPad Air 2"` | +| **rnipada3** | `react-native run-ios --simulator "iPad Air (3rd generation)"` | +| **rnipadm2** | `react-native run-ios --simulator "iPad mini 2"` | +| **rnipadm3** | `react-native run-ios --simulator "iPad mini 3"` | +| **rnipadm4** | `react-native run-ios --simulator "iPad mini 4"` | +| **rnipadm5** | `react-native run-ios --simulator "iPad mini (5th generation)"` | +| **rnipadp9** | `react-native run-ios --simulator "iPad Pro (9.7-inch)"` | +| **rnipadp12** | `react-native run-ios --simulator "iPad Pro (12.9-inch)"` | +| **rnipadp122** | `react-native run-ios --simulator "iPad Pro (12.9-inch) (2nd generation)"` | +| **rnipadp10** | `react-native run-ios --simulator "iPad Pro (10.5-inch)"` | +| **rnipad11** | `react-native run-ios --simulator "iPad Pro (11-inch)"` | +| **rnipad123** | `react-native run-ios --simulator "iPad Pro (12.9-inch) (3rd generation)"` | +| _Apple TV_ | | +| **rnatv** | `react-native run-ios --simulator "Apple TV"` | +| **rnatv4k** | `react-native run-ios --simulator "Apple TV 4K"` | +| **rnatv4k1080** | `react-native run-ios --simulator "Apple TV 4K (at 1080p)"` | +| **rnipad123** | `react-native run-ios --simulator "iPad Pro (12.9-inch) (3rd generation)"` | +| _Apple Watch_ | | +| **rnaw38** | `react-native run-ios --simulator "Apple Watch - 38mm"` | +| **rnaw42** | `react-native run-ios --simulator "Apple Watch - 42mm"` | +| **rnaws238** | `react-native run-ios --simulator "Apple Watch Series 2 - 38mm"` | +| **rnaws242** | `react-native run-ios --simulator "Apple Watch Series 2 - 42mm"` | +| **rnaws338** | `react-native run-ios --simulator "Apple Watch Series 3 - 38mm"` | +| **rnaws342** | `react-native run-ios --simulator "Apple Watch Series 3 - 42mm"` | +| **rnaws440** | `react-native run-ios --simulator "Apple Watch Series 4 - 40mm"` | +| **rnaws444** | `react-native run-ios --simulator "Apple Watch Series 4 - 44mm"` | diff --git a/plugins/react-native/react-native.plugin.zsh b/plugins/react-native/react-native.plugin.zsh index 8323c27bd..9ee081248 100644 --- a/plugins/react-native/react-native.plugin.zsh +++ b/plugins/react-native/react-native.plugin.zsh @@ -28,9 +28,21 @@ alias rnios11='react-native run-ios --simulator "iPhone 11"' alias rnios11p='react-native run-ios --simulator "iPhone 11 Pro"' alias rnios11pm='react-native run-ios --simulator "iPhone 11 Pro Max"' alias rnios12='react-native run-ios --simulator "iPhone 12"' +alias rnios12m='react-native run-ios --simulator "iPhone 12 mini"' alias rnios12p='react-native run-ios --simulator "iPhone 12 Pro"' alias rnios12pm='react-native run-ios --simulator "iPhone 12 Pro Max"' - +alias rnios13='react-native run-ios --simulator "iPhone 13"' +alias rnios13m='react-native run-ios --simulator "iPhone 13 mini"' +alias rnios13p='react-native run-ios --simulator "iPhone 13 Pro"' +alias rnios13pm='react-native run-ios --simulator "iPhone 13 Pro Max"' +alias rnios14='react-native run-ios --simulator "iPhone 14"' +alias rnios14pl='react-native run-ios --simulator "iPhone 14 Plus"' +alias rnios14p='react-native run-ios --simulator "iPhone 14 Pro"' +alias rnios14pm='react-native run-ios --simulator "iPhone 14 Pro Max"' +alias rnios15='react-native run-ios --simulator "iPhone 15"' +alias rnios15pl='react-native run-ios --simulator "iPhone 15 Plus"' +alias rnios15p='react-native run-ios --simulator "iPhone 15 Pro"' +alias rnios15pm='react-native run-ios --simulator "iPhone 15 Pro Max"' # iPad alias rnipad2='react-native run-ios --simulator "iPad 2"' diff --git a/plugins/ripgrep/_ripgrep b/plugins/ripgrep/_ripgrep index 31bc697c7..a93a8b8eb 100644 --- a/plugins/ripgrep/_ripgrep +++ b/plugins/ripgrep/_ripgrep @@ -591,7 +591,7 @@ _rg "$@" ################################################################################ # ------------------------------------------------------------------------------ -# Copyright (c) 2011 Github zsh-users - http://github.com/zsh-users +# Copyright (c) 2011 GitHub zsh-users - http://github.com/zsh-users # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/plugins/rtx/README.md b/plugins/rtx/README.md new file mode 100644 index 000000000..c6436d3a7 --- /dev/null +++ b/plugins/rtx/README.md @@ -0,0 +1,30 @@ +## rtx + + +Adds integration with [rtx](https://github.com/jdx/rtx), a runtime executor compatible with npm, nodenv, pyenv, etc. rtx is written in rust and is very fast. 20x-200x faster than asdf. With that being said, rtx is compatible with asdf plugins and .tool-versions files. It can be used as a drop-in replacement. + +### Installation + +1. [Download & install rtx](https://github.com/jdx/rtx#installation) by running the following: + + ``` + curl https://rtx.pub/install.sh | sh + ``` + + +2. [Enable rtx](https://github.com/jdx/rtx#quickstart) by adding it to your `plugins` definition in `~/.zshrc`. + + ``` + plugins=(rtx) + ``` + +### Usage + +See the [rtx readme](https://github.com/jdx/rtx#table-of-contents) for information on how to use rtx. Here are a few examples: + +``` +rtx install node Install the current version specified in .tool-versions/.rtx.toml +rtx use -g node@system Use system node as global default +rtx install node@20.0.0 Install a specific version number +rtx use -g node@20 Use node-20.x as global default +``` diff --git a/plugins/rtx/rtx.plugin.zsh b/plugins/rtx/rtx.plugin.zsh new file mode 100644 index 000000000..a01828afd --- /dev/null +++ b/plugins/rtx/rtx.plugin.zsh @@ -0,0 +1,18 @@ +# rtx needs to be in $PATH +if (( ! ${+commands[rtx]} )); then + return +fi + +# Load rtx hooks +eval "$(rtx activate zsh)" + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `rtx`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_rtx" ]]; then + typeset -g -A _comps + autoload -Uz _rtx + _comps[rtx]=_rtx +fi + +# Generate and load rtx completion +rtx completion zsh >! "$ZSH_CACHE_DIR/completions/_rtx" &| diff --git a/plugins/ruby/ruby.plugin.zsh b/plugins/ruby/ruby.plugin.zsh index 408512110..e09b22c75 100644 --- a/plugins/ruby/ruby.plugin.zsh +++ b/plugins/ruby/ruby.plugin.zsh @@ -23,4 +23,4 @@ alias gel="gem lock" alias geo="gem open" alias geoe="gem open -e" alias rrun="ruby -e" -alias rserver="ruby -e httpd . -p 8080" # requires webrick +alias rserver="ruby -run -e httpd . -p 8080" # requires webrick diff --git a/plugins/rvm/README.md b/plugins/rvm/README.md index 576b037b0..410bd60c0 100644 --- a/plugins/rvm/README.md +++ b/plugins/rvm/README.md @@ -24,6 +24,7 @@ plugins=(... rvm) | `rb27` | `rvm use ruby-2.7` | | `rb30` | `rvm use ruby-3.0` | | `rb31` | `rvm use ruby-3.1` | +| `rb32` | `rvm use ruby-3.2` | | `rvm-update` | `rvm get head` | | `gems` | `gem list` | | `rvms` | `rvm gemset` | diff --git a/plugins/rvm/rvm.plugin.zsh b/plugins/rvm/rvm.plugin.zsh index 2a091d019..3ddf04176 100644 --- a/plugins/rvm/rvm.plugin.zsh +++ b/plugins/rvm/rvm.plugin.zsh @@ -27,6 +27,7 @@ rubies=( 27 'ruby-2.7' 30 'ruby-3.0' 31 'ruby-3.1' + 32 'ruby-3.2' ) for v in ${(k)rubies}; do diff --git a/plugins/salt/_salt b/plugins/salt/_salt index a1c55f350..589d21d8b 100644 --- a/plugins/salt/_salt +++ b/plugins/salt/_salt @@ -9,7 +9,7 @@ # zstyle ':completion::complete:salt(|-call):modules:' use-cache true # zstyle ':completion::complete:salt(|-cp|-call|-run|-key):salt_dir:' use-cache true # -# cache validation can be controled with the style cache-ttl. +# cache validation can be controlled with the style cache-ttl. # it expects two arguments: number (days|hours|weeks|months) # to invalidate the minion cache after four days: # zstyle ':completion::complete:salt(|-cp|-call):minions:' cache-ttl 4 days diff --git a/plugins/scala/_scala b/plugins/scala/_scala index ba7ac3874..b4e834e2f 100644 --- a/plugins/scala/_scala +++ b/plugins/scala/_scala @@ -1,6 +1,6 @@ #compdef scala scalac # ------------------------------------------------------------------------------ -# Copyright (c) 2012 Github zsh-users - https://github.com/zsh-users +# Copyright (c) 2012 GitHub zsh-users - https://github.com/zsh-users # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/plugins/shell-proxy/README.md b/plugins/shell-proxy/README.md index b19888c56..102e46b6b 100644 --- a/plugins/shell-proxy/README.md +++ b/plugins/shell-proxy/README.md @@ -23,6 +23,7 @@ Set `SHELLPROXY_URL` environment variable to the URL of the proxy server: ```sh SHELLPROXY_URL="http://127.0.0.1:8123" +SHELLPROXY_NO_PROXY="localhost,127.0.0.1" proxy enable ``` @@ -36,11 +37,15 @@ Example: ```sh #!/bin/bash +# HTTP Proxy if [[ "$(uname)" = Darwin ]]; then echo "http://127.0.0.1:6152" # Surge Mac else echo "http://127.0.0.1:8123" # polipo fi + +# No Proxy +echo "localhost,127.0.0.1" ``` ### Method 3 diff --git a/plugins/shell-proxy/proxy.py b/plugins/shell-proxy/proxy.py index 14f2944cc..8c2aaf9f3 100755 --- a/plugins/shell-proxy/proxy.py +++ b/plugins/shell-proxy/proxy.py @@ -6,6 +6,7 @@ from subprocess import check_output, list2cmdline cwd = os.path.dirname(__file__) ssh_agent = os.path.join(cwd, "ssh-agent.py") proxy_env = "SHELLPROXY_URL" +no_proxy_env = "SHELLPROXY_NO_PROXY" proxy_config = os.environ.get("SHELLPROXY_CONFIG") or os.path.expandvars("$HOME/.config/proxy") usage="""shell-proxy: no proxy configuration found. @@ -15,18 +16,30 @@ See the plugin README for more information.""".format(env=proxy_env, config=prox def get_http_proxy(): default_proxy = os.environ.get(proxy_env) - if default_proxy: - return default_proxy + no_proxy = os.environ.get(no_proxy_env) + if default_proxy and no_proxy: + return default_proxy, no_proxy + if os.path.isfile(proxy_config): - return check_output(proxy_config).decode("utf-8").strip() + proxy_configdata = [line.strip() for line in check_output(proxy_config).decode("utf-8").splitlines()] + if len(proxy_configdata) >= 1: + if not default_proxy: + default_proxy = proxy_configdata[0] + if len(proxy_configdata) == 2 and not no_proxy: + no_proxy = proxy_configdata[1] + + if default_proxy: + return default_proxy, no_proxy print(usage, file=sys.stderr) sys.exit(1) -def make_proxies(url: str): +def make_proxies(url: str, no_proxy: str): proxies = {"%s_PROXY" % _: url for _ in ("HTTP", "HTTPS", "FTP", "RSYNC", "ALL")} proxies.update({name.lower(): value for (name, value) in proxies.items()}) proxies["GIT_SSH"] = ssh_agent + if no_proxy: + proxies.update({"NO_PROXY": no_proxy, "no_proxy": no_proxy}) return proxies @@ -35,7 +48,7 @@ def merge(mapping: dict): class CommandSet: - proxies = make_proxies(get_http_proxy()) + proxies = make_proxies(*get_http_proxy()) aliases = { _: "env __SSH_PROGRAM_NAME__=%s %s" % (_, ssh_agent) for _ in ("ssh", "sftp", "scp", "slogin", "ssh-copy-id") diff --git a/plugins/shell-proxy/shell-proxy.plugin.zsh b/plugins/shell-proxy/shell-proxy.plugin.zsh index 4fdbe9322..f6c31da45 100644 --- a/plugins/shell-proxy/shell-proxy.plugin.zsh +++ b/plugins/shell-proxy/shell-proxy.plugin.zsh @@ -27,7 +27,7 @@ eval ' # capture the output of the proxy script and bail out if it fails local output - output="$(SHELLPROXY_URL="$SHELLPROXY_URL" SHELLPROXY_CONFIG="$SHELLPROXY_CONFIG" "$proxy" "$1")" || + output="$(SHELLPROXY_URL="$SHELLPROXY_URL" SHELLPROXY_NO_PROXY="$SHELLPROXY_NO_PROXY" SHELLPROXY_CONFIG="$SHELLPROXY_CONFIG" "$proxy" "$1")" || return $? # evaluate the output generated by the proxy script diff --git a/plugins/sigstore/README.md b/plugins/sigstore/README.md new file mode 100644 index 000000000..00e83c8c2 --- /dev/null +++ b/plugins/sigstore/README.md @@ -0,0 +1,13 @@ +# Sigstore plugin + +This plugin sets up completion for the following [Sigstore](https://sigstore.dev/) CLI tools. + +- [Cosign](https://docs.sigstore.dev/cosign/overview) +- [Sget](https://docs.sigstore.dev/cosign/installation#alpine-linux) +- [Rekor](https://docs.sigstore.dev/rekor/overview) + +To use it, add `sigstore` to the plugins array in your zshrc file: + +```zsh +plugins=(... sigstore) +``` diff --git a/plugins/sigstore/sigstore.plugin.zsh b/plugins/sigstore/sigstore.plugin.zsh new file mode 100644 index 000000000..1f9d77c11 --- /dev/null +++ b/plugins/sigstore/sigstore.plugin.zsh @@ -0,0 +1,22 @@ +function install_autocompletion { + if (( ! $+commands[$1] )); then + return + fi + + # If the completion file doesn't exist yet, we need to autoload it and + # bind it to `$1` (cosign, sget, rekor-cli). Otherwise, compinit will + # have already done that + if [[ ! -f "$ZSH_CACHE_DIR/completions/_$1" ]]; then + autoload -Uz _$1 + typeset -g -A _comps + _comps[$1]=_$1 + fi + + $1 completion zsh >| "$ZSH_CACHE_DIR/completions/_$1" &| +} + +install_autocompletion cosign +install_autocompletion sget +install_autocompletion rekor-cli + +unfunction install_autocompletion diff --git a/plugins/skaffold/README.md b/plugins/skaffold/README.md new file mode 100644 index 000000000..4ee12c666 --- /dev/null +++ b/plugins/skaffold/README.md @@ -0,0 +1,9 @@ +# Skaffold plugin (Autocompletion) + +This plugin adds completion for [Skaffold](https://skaffold.dev) + +To use it, add `skaffold` to the plugins array in your zshrc file: + +```zsh +plugins=(... skaffold) +``` diff --git a/plugins/skaffold/skaffold.plugin.zsh b/plugins/skaffold/skaffold.plugin.zsh new file mode 100644 index 000000000..8296c450c --- /dev/null +++ b/plugins/skaffold/skaffold.plugin.zsh @@ -0,0 +1,14 @@ +# Autocompletion for skaffold +if (( ! $+commands[skaffold] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `skaffold`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_skaffold" ]]; then + typeset -g -A _comps + autoload -Uz _skaffold + _comps[skaffold]=_skaffold +fi + +skaffold completion zsh >| "$ZSH_CACHE_DIR/completions/_skaffold" &| diff --git a/plugins/snap/README.md b/plugins/snap/README.md new file mode 100644 index 000000000..75c5ec19a --- /dev/null +++ b/plugins/snap/README.md @@ -0,0 +1,18 @@ +# snap plugin + +This plugin sets up aliases for the common [snap](https://snapcraft.io/docs/getting-started) commands + +## Aliases + +| Alias | Full command | +| --- | ---| +| sv | snap version | +| sf | snap find | +| si | snap install | +| sin | snap info | +| sr | snap remove | +| sref | snap refresh | +| srev | snap revert | +| sl | snap list | +| sd | snap disable | +| se | snap enable | diff --git a/plugins/snap/snap.plugin.zsh b/plugins/snap/snap.plugin.zsh new file mode 100644 index 000000000..af2346978 --- /dev/null +++ b/plugins/snap/snap.plugin.zsh @@ -0,0 +1,10 @@ +alias sv="snap version" +alias sf="snap find" +alias si="snap install" +alias sin="snap info" +alias sr="snap remove" +alias sref="snap refresh" +alias srev="snap revert" +alias sl="snap list" +alias sd="snap disable" +alias se="snap enable" diff --git a/plugins/ssh-agent/README.md b/plugins/ssh-agent/README.md index fa6a996d4..8c118e65b 100644 --- a/plugins/ssh-agent/README.md +++ b/plugins/ssh-agent/README.md @@ -99,6 +99,33 @@ ssh-add -K -c -a /run/user/1000/ssh-auth For valid `ssh-add` arguments run `ssh-add --help` or `man ssh-add`. +### Powerline 10k specific settings + +Powerline10k has an instant prompt setting that doesn't like when this plugin +writes to the console. Consider using the following settings if you're using +p10k (documented above): + +``` +zstyle :omz:plugins:ssh-agent quiet yes +zstyle :omz:plugins:ssh-agent lazy yes +``` + +### macOS specific settings + +macOS supports using passphrases stored in the keychain when adding identities +to the ssh-agent. + +``` +ssh-add --apple-use-keychain ~/.ssh/id_rsa ... +``` + + +This plugin can be configured to use the keychain when loading using the following: + +``` +zstyle :omz:plugins:ssh-agent ssh-add-args --apple-load-keychain +``` + ## Credits Based on code from Joseph M. Reagle: https://www.cygwin.com/ml/cygwin/2001-06/msg00537.html diff --git a/plugins/ssh-agent/ssh-agent.plugin.zsh b/plugins/ssh-agent/ssh-agent.plugin.zsh index 0d6a35b35..49ad95a11 100644 --- a/plugins/ssh-agent/ssh-agent.plugin.zsh +++ b/plugins/ssh-agent/ssh-agent.plugin.zsh @@ -13,6 +13,11 @@ function _start_agent() { fi fi + if [[ ! -d "$HOME/.ssh" ]]; then + echo "[oh-my-zsh] ssh-agent plugin requires ~/.ssh directory" + return 1 + fi + # Set a maximum lifetime for identities added to ssh-agent local lifetime zstyle -s :omz:plugins:ssh-agent lifetime lifetime @@ -72,6 +77,9 @@ function _add_identities() { local args zstyle -a :omz:plugins:ssh-agent ssh-add-args args + # if ssh-agent quiet mode, pass -q to ssh-add + zstyle -t :omz:plugins:ssh-agent quiet && args=(-q $args) + # use user specified helper to ask for password (ksshaskpass, etc) local helper zstyle -s :omz:plugins:ssh-agent helper helper diff --git a/plugins/starship/README.md b/plugins/starship/README.md new file mode 100644 index 000000000..0e66c5294 --- /dev/null +++ b/plugins/starship/README.md @@ -0,0 +1,21 @@ +# starship plugin + +Initializes [starship prompt](https://starship.rs) - a minimal, blazing-fast and infinitely customizable cross-shell prompt. + +[Demo](https://user-images.githubusercontent.com/62098008/169764279-50b48262-9506-4651-ba89-f6611a88ebf0.mp4) + +[External repository](https://github.com/axieax/zsh-starship) for this zsh plugin. + +# Installation + +**Note:** you have to [install starship](https://starship.rs/guide/#%F0%9F%9A%80-installation) first. + +## [oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh) + +Add `starship` to the plugins array in your `.zshrc` file: + +```zsh +plugins=(... starship) +``` + +## ⚠️ ENABLING THIS PLUGIN WILL UNSET YOUR ZSH_THEME VARIABLE diff --git a/plugins/starship/starship.plugin.zsh b/plugins/starship/starship.plugin.zsh new file mode 100644 index 000000000..8c5d9135e --- /dev/null +++ b/plugins/starship/starship.plugin.zsh @@ -0,0 +1,8 @@ +# ignore oh-my-zsh theme +unset ZSH_THEME + +if (( $+commands[starship] )); then + eval "$(starship init zsh)" +else + echo '[oh-my-zsh] starship not found, please install it from https://starship.rs' +fi diff --git a/plugins/sudo/sudo.plugin.zsh b/plugins/sudo/sudo.plugin.zsh index 2a0b3bfc4..66b253fe7 100644 --- a/plugins/sudo/sudo.plugin.zsh +++ b/plugins/sudo/sudo.plugin.zsh @@ -96,7 +96,7 @@ sudo-command-line() { LBUFFER="${WHITESPACE}${LBUFFER}" # Redisplay edit buffer (compatibility with zsh-syntax-highlighting) - zle redisplay + zle && zle redisplay # only run redisplay if zle is enabled } } diff --git a/plugins/swiftpm/README.md b/plugins/swiftpm/README.md index a722c03e4..223a607c1 100644 --- a/plugins/swiftpm/README.md +++ b/plugins/swiftpm/README.md @@ -2,7 +2,7 @@ ## Description -This plugin provides a few utilities that make you faster on your daily work with the [Swift Package Manager](https://github.com/apple/swift-package-manager), as well as autocompletion for Swift 5.1. +This plugin provides a few utilities that make you faster on your daily work with the [Swift Package Manager](https://github.com/apple/swift-package-manager), as well as autocompletion for Swift 5.7. To start using it, add the `swiftpm` plugin to your `plugins` array in `~/.zshrc`: diff --git a/plugins/swiftpm/_swift b/plugins/swiftpm/_swift index fe6f1c9aa..51c9fffa0 100644 --- a/plugins/swiftpm/_swift +++ b/plugins/swiftpm/_swift @@ -1,474 +1,876 @@ #compdef swift local context state state_descr line +_swift_commandname=$words[1] typeset -A opt_args _swift() { - _arguments -C \ - '(- :)--help[prints the synopsis and a list of the most commonly used commands]: :->arg' \ - '(-): :->command' \ - '(-)*:: :->arg' && return - + integer ret=1 + local -a args + args+=( + '(-h --help)'{-h,--help}'[Show help information.]' + '(-): :->command' + '(-)*:: :->arg' + ) + _arguments -w -s -S $args[@] && ret=0 case $state in (command) - local tools - tools=( - 'build:build sources into binary products' - 'run:build and run an executable product' - 'package:perform operations on Swift packages' - 'test:build and run tests' + local subcommands + subcommands=( + 'run:Build and run an executable product' + 'build:Build sources into binary products' + 'test:Build and run tests' + 'package:Perform operations on Swift packages' + 'help:Show subcommand help information.' ) - _alternative \ - 'tools:common:{_describe "tool" tools }' \ - 'compiler: :_swift_compiler' && _ret=0 + _describe "subcommand" subcommands ;; (arg) case ${words[1]} in - (build) - _swift_build - ;; (run) _swift_run ;; - (package) - _swift_package + (build) + _swift_build ;; (test) _swift_test ;; - (*) - _swift_compiler + (package) + _swift_package + ;; + (help) + _swift_help ;; esac ;; esac + + return ret } -_swift_dependency() { - local dependencies - dependencies=( $(swift package completion-tool list-dependencies) ) - _describe '' dependencies -} - -_swift_executable() { - local executables - executables=( $(swift package completion-tool list-executables) ) - _describe '' executables -} - -# Generates completions for swift build -# -# In the final compdef file, set the following file header: -# -# #compdef _swift_build -# local context state state_descr line -# typeset -A opt_args -_swift_build() { - arguments=( - "-Xcc[Pass flag through to all C compiler invocations]:Pass flag through to all C compiler invocations: " - "-Xswiftc[Pass flag through to all Swift compiler invocations]:Pass flag through to all Swift compiler invocations: " - "-Xlinker[Pass flag through to all linker invocations]:Pass flag through to all linker invocations: " - "-Xcxx[Pass flag through to all C++ compiler invocations]:Pass flag through to all C++ compiler invocations: " - "(--configuration -c)"{--configuration,-c}"[Build with configuration (debug|release) ]: :{_values '' 'debug[build with DEBUG configuration]' 'release[build with RELEASE configuration]'}" - "--build-path[Specify build/cache directory ]:Specify build/cache directory :_files" - "(--chdir -C)"{--chdir,-C}"[]: :_files" - "--package-path[Change working directory before any other operation]:Change working directory before any other operation:_files" - "--sanitize[Turn on runtime checks for erroneous behavior]: :{_values '' 'address[enable Address sanitizer]' 'thread[enable Thread sanitizer]' 'undefined[enable Undefined Behavior sanitizer]'}" - "--disable-prefetching[]" - "--skip-update[Skip updating dependencies from their remote during a resolution]" - "--disable-sandbox[Disable using the sandbox when executing subprocesses]" - "--disable-package-manifest-caching[Disable caching Package.swift manifests]" - "--version[]" - "--destination[]: :_files" - "(--verbose -v)"{--verbose,-v}"[Increase verbosity of informational output]" - "--no-static-swift-stdlib[Do not link Swift stdlib statically \[default\]]" - "--static-swift-stdlib[Link Swift stdlib statically]" - "--force-resolved-versions[]" - "--disable-automatic-resolution[Disable automatic resolution if Package.resolved file is out-of-date]" - "--enable-index-store[Enable indexing-while-building feature]" - "--disable-index-store[Disable indexing-while-building feature]" - "--enable-pubgrub-resolver[\[Experimental\] Enable the new Pubgrub dependency resolver]" - "--enable-parseable-module-interfaces[]" - "--trace-resolver[]" - "(--jobs -j)"{--jobs,-j}"[The number of jobs to spawn in parallel during the build process]:The number of jobs to spawn in parallel during the build process: " - "--enable-test-discovery[Enable test discovery on platforms without Objective-C runtime]" - "--build-tests[Build both source and test targets]" - "--product[Build the specified product]:Build the specified product: " - "--target[Build the specified target]:Build the specified target: " - "--show-bin-path[Print the binary output path]" - ) - _arguments $arguments && return -} - -# Generates completions for swift run -# -# In the final compdef file, set the following file header: -# -# #compdef _swift_run -# local context state state_descr line -# typeset -A opt_args _swift_run() { - arguments=( - ":The executable to run:_swift_executable" - "-Xcc[Pass flag through to all C compiler invocations]:Pass flag through to all C compiler invocations: " - "-Xswiftc[Pass flag through to all Swift compiler invocations]:Pass flag through to all Swift compiler invocations: " - "-Xlinker[Pass flag through to all linker invocations]:Pass flag through to all linker invocations: " - "-Xcxx[Pass flag through to all C++ compiler invocations]:Pass flag through to all C++ compiler invocations: " - "(--configuration -c)"{--configuration,-c}"[Build with configuration (debug|release) ]: :{_values '' 'debug[build with DEBUG configuration]' 'release[build with RELEASE configuration]'}" - "--build-path[Specify build/cache directory ]:Specify build/cache directory :_files" - "(--chdir -C)"{--chdir,-C}"[]: :_files" - "--package-path[Change working directory before any other operation]:Change working directory before any other operation:_files" - "--sanitize[Turn on runtime checks for erroneous behavior]: :{_values '' 'address[enable Address sanitizer]' 'thread[enable Thread sanitizer]' 'undefined[enable Undefined Behavior sanitizer]'}" - "--disable-prefetching[]" - "--skip-update[Skip updating dependencies from their remote during a resolution]" - "--disable-sandbox[Disable using the sandbox when executing subprocesses]" - "--disable-package-manifest-caching[Disable caching Package.swift manifests]" - "--version[]" - "--destination[]: :_files" - "(--verbose -v)"{--verbose,-v}"[Increase verbosity of informational output]" - "--no-static-swift-stdlib[Do not link Swift stdlib statically \[default\]]" - "--static-swift-stdlib[Link Swift stdlib statically]" - "--force-resolved-versions[]" - "--disable-automatic-resolution[Disable automatic resolution if Package.resolved file is out-of-date]" - "--enable-index-store[Enable indexing-while-building feature]" - "--disable-index-store[Disable indexing-while-building feature]" - "--enable-pubgrub-resolver[\[Experimental\] Enable the new Pubgrub dependency resolver]" - "--enable-parseable-module-interfaces[]" - "--trace-resolver[]" - "(--jobs -j)"{--jobs,-j}"[The number of jobs to spawn in parallel during the build process]:The number of jobs to spawn in parallel during the build process: " - "--enable-test-discovery[Enable test discovery on platforms without Objective-C runtime]" - "--skip-build[Skip building the executable product]" - "--build-tests[Build both source and test targets]" - "--repl[Launch Swift REPL for the package]" + integer ret=1 + local -a args + args+=( + '--package-path[Specify the package path to operate on (default current directory). This changes the working directory before any other operation]:package-path:_files -/' + '--cache-path[Specify the shared cache directory path]:cache-path:_files -/' + '--config-path[Specify the shared configuration directory path]:config-path:_files -/' + '--security-path[Specify the shared security directory path]:security-path:_files -/' + '--scratch-path[Specify a custom scratch directory path (default .build)]:scratch-path:_files -/' + '--enable-dependency-cache[Use a shared cache when fetching dependencies]' + '--disable-dependency-cache[Use a shared cache when fetching dependencies]' + '--enable-build-manifest-caching' + '--disable-build-manifest-caching' + '--manifest-cache[Caching mode of Package.swift manifests (shared: shared cache, local: package'"'"'s build directory, none: disabled]:manifest-cache:' + '(--verbose -v)'{--verbose,-v}'[Increase verbosity to include informational output]' + '(--very-verbose --vv)'{--very-verbose,--vv}'[Increase verbosity to include debug output]' + '--disable-sandbox[Disable using the sandbox when executing subprocesses]' + '--enable-netrc[Load credentials from a .netrc file]' + '--disable-netrc[Load credentials from a .netrc file]' + '--netrc-file[Specify the .netrc file path.]:netrc-file:_files' + '--enable-keychain[Search credentials in macOS keychain]' + '--disable-keychain[Search credentials in macOS keychain]' + '--resolver-fingerprint-checking:resolver-fingerprint-checking:' + '--enable-prefetching' + '--disable-prefetching' + '(--force-resolved-versions --disable-automatic-resolution --only-use-versions-from-resolved-file)'{--force-resolved-versions,--disable-automatic-resolution,--only-use-versions-from-resolved-file}'[Only use versions from the Package.resolved file and fail resolution if it is out-of-date]' + '--skip-update[Skip updating dependencies from their remote during a resolution]' + '--disable-scm-to-registry-transformation[disable source control to registry transformation]' + '--use-registry-identity-for-scm[look up source control dependencies in the registry and use their registry identity when possible to help deduplicate across the two origins]' + '--replace-scm-with-registry[look up source control dependencies in the registry and use the registry to retrieve them instead of source control when possible]' + '(--configuration -c)'{--configuration,-c}'[Build with configuration]:configuration:(debug release)' + '-Xcc[Pass flag through to all C compiler invocations]:Xcc:' + '-Xswiftc[Pass flag through to all Swift compiler invocations]:Xswiftc:' + '-Xlinker[Pass flag through to all linker invocations]:Xlinker:' + '-Xcxx[Pass flag through to all C++ compiler invocations]:Xcxx:' + '--triple:triple:' + '--sdk:sdk:_files -/' + '--toolchain:toolchain:_files -/' + '--sanitize[Turn on runtime checks for erroneous behavior, possible values: address, thread, undefined, scudo]:sanitize:' + '--auto-index-store[Enable or disable indexing-while-building feature]' + '--enable-index-store[Enable or disable indexing-while-building feature]' + '--disable-index-store[Enable or disable indexing-while-building feature]' + '--enable-parseable-module-interfaces' + '(--jobs -j)'{--jobs,-j}'[The number of jobs to spawn in parallel during the build process]:jobs:' + '--emit-swift-module-separately' + '--use-integrated-swift-driver' + '--experimental-explicit-module-build' + '--print-manifest-job-graph[Write the command graph for the build manifest as a graphviz file]' + '--build-system:build-system:(native xcode)' + '--enable-dead-strip[Disable/enable dead code stripping by the linker]' + '--disable-dead-strip[Disable/enable dead code stripping by the linker]' + '--static-swift-stdlib[Link Swift stdlib statically]' + '--no-static-swift-stdlib[Link Swift stdlib statically]' + '--repl[Launch Swift REPL for the package]' + '--debugger[Launch the executable in a debugger session]' + '--run[Launch the executable with the provided arguments]' + '--skip-build[Skip building the executable product]' + '--build-tests[Build both source and test targets]' + ':executable:{local -a list; list=(${(f)"$(swift package completion-tool list-executables)"}); _describe '''' list}' + ':arguments:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_build() { + integer ret=1 + local -a args + args+=( + '--package-path[Specify the package path to operate on (default current directory). This changes the working directory before any other operation]:package-path:_files -/' + '--cache-path[Specify the shared cache directory path]:cache-path:_files -/' + '--config-path[Specify the shared configuration directory path]:config-path:_files -/' + '--security-path[Specify the shared security directory path]:security-path:_files -/' + '--scratch-path[Specify a custom scratch directory path (default .build)]:scratch-path:_files -/' + '--enable-dependency-cache[Use a shared cache when fetching dependencies]' + '--disable-dependency-cache[Use a shared cache when fetching dependencies]' + '--enable-build-manifest-caching' + '--disable-build-manifest-caching' + '--manifest-cache[Caching mode of Package.swift manifests (shared: shared cache, local: package'"'"'s build directory, none: disabled]:manifest-cache:' + '(--verbose -v)'{--verbose,-v}'[Increase verbosity to include informational output]' + '(--very-verbose --vv)'{--very-verbose,--vv}'[Increase verbosity to include debug output]' + '--disable-sandbox[Disable using the sandbox when executing subprocesses]' + '--enable-netrc[Load credentials from a .netrc file]' + '--disable-netrc[Load credentials from a .netrc file]' + '--netrc-file[Specify the .netrc file path.]:netrc-file:_files' + '--enable-keychain[Search credentials in macOS keychain]' + '--disable-keychain[Search credentials in macOS keychain]' + '--resolver-fingerprint-checking:resolver-fingerprint-checking:' + '--enable-prefetching' + '--disable-prefetching' + '(--force-resolved-versions --disable-automatic-resolution --only-use-versions-from-resolved-file)'{--force-resolved-versions,--disable-automatic-resolution,--only-use-versions-from-resolved-file}'[Only use versions from the Package.resolved file and fail resolution if it is out-of-date]' + '--skip-update[Skip updating dependencies from their remote during a resolution]' + '--disable-scm-to-registry-transformation[disable source control to registry transformation]' + '--use-registry-identity-for-scm[look up source control dependencies in the registry and use their registry identity when possible to help deduplicate across the two origins]' + '--replace-scm-with-registry[look up source control dependencies in the registry and use the registry to retrieve them instead of source control when possible]' + '(--configuration -c)'{--configuration,-c}'[Build with configuration]:configuration:(debug release)' + '-Xcc[Pass flag through to all C compiler invocations]:Xcc:' + '-Xswiftc[Pass flag through to all Swift compiler invocations]:Xswiftc:' + '-Xlinker[Pass flag through to all linker invocations]:Xlinker:' + '-Xcxx[Pass flag through to all C++ compiler invocations]:Xcxx:' + '--triple:triple:' + '--sdk:sdk:_files -/' + '--toolchain:toolchain:_files -/' + '--sanitize[Turn on runtime checks for erroneous behavior, possible values: address, thread, undefined, scudo]:sanitize:' + '--auto-index-store[Enable or disable indexing-while-building feature]' + '--enable-index-store[Enable or disable indexing-while-building feature]' + '--disable-index-store[Enable or disable indexing-while-building feature]' + '--enable-parseable-module-interfaces' + '(--jobs -j)'{--jobs,-j}'[The number of jobs to spawn in parallel during the build process]:jobs:' + '--emit-swift-module-separately' + '--use-integrated-swift-driver' + '--experimental-explicit-module-build' + '--print-manifest-job-graph[Write the command graph for the build manifest as a graphviz file]' + '--build-system:build-system:(native xcode)' + '--enable-dead-strip[Disable/enable dead code stripping by the linker]' + '--disable-dead-strip[Disable/enable dead code stripping by the linker]' + '--static-swift-stdlib[Link Swift stdlib statically]' + '--no-static-swift-stdlib[Link Swift stdlib statically]' + '--build-tests[Build both source and test targets]' + '--show-bin-path[Print the binary output path]' + '--target[Build the specified target]:target:' + '--product[Build the specified product]:product:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_test() { + integer ret=1 + local -a args + args+=( + '--package-path[Specify the package path to operate on (default current directory). This changes the working directory before any other operation]:package-path:_files -/' + '--cache-path[Specify the shared cache directory path]:cache-path:_files -/' + '--config-path[Specify the shared configuration directory path]:config-path:_files -/' + '--security-path[Specify the shared security directory path]:security-path:_files -/' + '--scratch-path[Specify a custom scratch directory path (default .build)]:scratch-path:_files -/' + '--enable-dependency-cache[Use a shared cache when fetching dependencies]' + '--disable-dependency-cache[Use a shared cache when fetching dependencies]' + '--enable-build-manifest-caching' + '--disable-build-manifest-caching' + '--manifest-cache[Caching mode of Package.swift manifests (shared: shared cache, local: package'"'"'s build directory, none: disabled]:manifest-cache:' + '(--verbose -v)'{--verbose,-v}'[Increase verbosity to include informational output]' + '(--very-verbose --vv)'{--very-verbose,--vv}'[Increase verbosity to include debug output]' + '--disable-sandbox[Disable using the sandbox when executing subprocesses]' + '--enable-netrc[Load credentials from a .netrc file]' + '--disable-netrc[Load credentials from a .netrc file]' + '--netrc-file[Specify the .netrc file path.]:netrc-file:_files' + '--enable-keychain[Search credentials in macOS keychain]' + '--disable-keychain[Search credentials in macOS keychain]' + '--resolver-fingerprint-checking:resolver-fingerprint-checking:' + '--enable-prefetching' + '--disable-prefetching' + '(--force-resolved-versions --disable-automatic-resolution --only-use-versions-from-resolved-file)'{--force-resolved-versions,--disable-automatic-resolution,--only-use-versions-from-resolved-file}'[Only use versions from the Package.resolved file and fail resolution if it is out-of-date]' + '--skip-update[Skip updating dependencies from their remote during a resolution]' + '--disable-scm-to-registry-transformation[disable source control to registry transformation]' + '--use-registry-identity-for-scm[look up source control dependencies in the registry and use their registry identity when possible to help deduplicate across the two origins]' + '--replace-scm-with-registry[look up source control dependencies in the registry and use the registry to retrieve them instead of source control when possible]' + '(--configuration -c)'{--configuration,-c}'[Build with configuration]:configuration:(debug release)' + '-Xcc[Pass flag through to all C compiler invocations]:Xcc:' + '-Xswiftc[Pass flag through to all Swift compiler invocations]:Xswiftc:' + '-Xlinker[Pass flag through to all linker invocations]:Xlinker:' + '-Xcxx[Pass flag through to all C++ compiler invocations]:Xcxx:' + '--triple:triple:' + '--sdk:sdk:_files -/' + '--toolchain:toolchain:_files -/' + '--sanitize[Turn on runtime checks for erroneous behavior, possible values: address, thread, undefined, scudo]:sanitize:' + '--auto-index-store[Enable or disable indexing-while-building feature]' + '--enable-index-store[Enable or disable indexing-while-building feature]' + '--disable-index-store[Enable or disable indexing-while-building feature]' + '--enable-parseable-module-interfaces' + '(--jobs -j)'{--jobs,-j}'[The number of jobs to spawn in parallel during the build process]:jobs:' + '--emit-swift-module-separately' + '--use-integrated-swift-driver' + '--experimental-explicit-module-build' + '--print-manifest-job-graph[Write the command graph for the build manifest as a graphviz file]' + '--build-system:build-system:(native xcode)' + '--enable-dead-strip[Disable/enable dead code stripping by the linker]' + '--disable-dead-strip[Disable/enable dead code stripping by the linker]' + '--static-swift-stdlib[Link Swift stdlib statically]' + '--no-static-swift-stdlib[Link Swift stdlib statically]' + '--skip-build[Skip building the test target]' + '--parallel[Run the tests in parallel.]' + '--num-workers[Number of tests to execute in parallel.]:num-workers:' + '(--list-tests -l)'{--list-tests,-l}'[Lists test methods in specifier format]' + '--show-codecov-path[Print the path of the exported code coverage JSON file]' + '(-s --specifier)'{-s,--specifier}':specifier:' + '--filter[Run test cases matching regular expression, Format: . or ./]:filter:' + '--skip[Skip test cases matching regular expression, Example: --skip PerformanceTests]:skip:' + '--xunit-output[Path where the xUnit xml file should be generated.]:xunit-output:_files -/' + '--test-product[Test the specified product.]:test-product:' + '--enable-testable-imports[Enable or disable testable imports. Enabled by default.]' + '--disable-testable-imports[Enable or disable testable imports. Enabled by default.]' + '--enable-code-coverage[Enable code coverage]' + '--disable-code-coverage[Enable code coverage]' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret } -# Generates completions for swift package -# -# In the final compdef file, set the following file header: -# -# #compdef _swift_package -# local context state state_descr line -# typeset -A opt_args _swift_package() { - arguments=( - "-Xcc[Pass flag through to all C compiler invocations]:Pass flag through to all C compiler invocations: " - "-Xswiftc[Pass flag through to all Swift compiler invocations]:Pass flag through to all Swift compiler invocations: " - "-Xlinker[Pass flag through to all linker invocations]:Pass flag through to all linker invocations: " - "-Xcxx[Pass flag through to all C++ compiler invocations]:Pass flag through to all C++ compiler invocations: " - "(--configuration -c)"{--configuration,-c}"[Build with configuration (debug|release) ]: :{_values '' 'debug[build with DEBUG configuration]' 'release[build with RELEASE configuration]'}" - "--build-path[Specify build/cache directory ]:Specify build/cache directory :_files" - "(--chdir -C)"{--chdir,-C}"[]: :_files" - "--package-path[Change working directory before any other operation]:Change working directory before any other operation:_files" - "--sanitize[Turn on runtime checks for erroneous behavior]: :{_values '' 'address[enable Address sanitizer]' 'thread[enable Thread sanitizer]' 'undefined[enable Undefined Behavior sanitizer]'}" - "--disable-prefetching[]" - "--skip-update[Skip updating dependencies from their remote during a resolution]" - "--disable-sandbox[Disable using the sandbox when executing subprocesses]" - "--disable-package-manifest-caching[Disable caching Package.swift manifests]" - "--version[]" - "--destination[]: :_files" - "(--verbose -v)"{--verbose,-v}"[Increase verbosity of informational output]" - "--no-static-swift-stdlib[Do not link Swift stdlib statically \[default\]]" - "--static-swift-stdlib[Link Swift stdlib statically]" - "--force-resolved-versions[]" - "--disable-automatic-resolution[Disable automatic resolution if Package.resolved file is out-of-date]" - "--enable-index-store[Enable indexing-while-building feature]" - "--disable-index-store[Disable indexing-while-building feature]" - "--enable-pubgrub-resolver[\[Experimental\] Enable the new Pubgrub dependency resolver]" - "--enable-parseable-module-interfaces[]" - "--trace-resolver[]" - "(--jobs -j)"{--jobs,-j}"[The number of jobs to spawn in parallel during the build process]:The number of jobs to spawn in parallel during the build process: " - "--enable-test-discovery[Enable test discovery on platforms without Objective-C runtime]" + integer ret=1 + local -a args + args+=( + '--package-path[Specify the package path to operate on (default current directory). This changes the working directory before any other operation]:package-path:_files -/' + '--cache-path[Specify the shared cache directory path]:cache-path:_files -/' + '--config-path[Specify the shared configuration directory path]:config-path:_files -/' + '--security-path[Specify the shared security directory path]:security-path:_files -/' + '--scratch-path[Specify a custom scratch directory path (default .build)]:scratch-path:_files -/' + '--enable-dependency-cache[Use a shared cache when fetching dependencies]' + '--disable-dependency-cache[Use a shared cache when fetching dependencies]' + '--enable-build-manifest-caching' + '--disable-build-manifest-caching' + '--manifest-cache[Caching mode of Package.swift manifests (shared: shared cache, local: package'"'"'s build directory, none: disabled]:manifest-cache:' + '(--verbose -v)'{--verbose,-v}'[Increase verbosity to include informational output]' + '(--very-verbose --vv)'{--very-verbose,--vv}'[Increase verbosity to include debug output]' + '--disable-sandbox[Disable using the sandbox when executing subprocesses]' + '--enable-netrc[Load credentials from a .netrc file]' + '--disable-netrc[Load credentials from a .netrc file]' + '--netrc-file[Specify the .netrc file path.]:netrc-file:_files' + '--enable-keychain[Search credentials in macOS keychain]' + '--disable-keychain[Search credentials in macOS keychain]' + '--resolver-fingerprint-checking:resolver-fingerprint-checking:' + '--enable-prefetching' + '--disable-prefetching' + '(--force-resolved-versions --disable-automatic-resolution --only-use-versions-from-resolved-file)'{--force-resolved-versions,--disable-automatic-resolution,--only-use-versions-from-resolved-file}'[Only use versions from the Package.resolved file and fail resolution if it is out-of-date]' + '--skip-update[Skip updating dependencies from their remote during a resolution]' + '--disable-scm-to-registry-transformation[disable source control to registry transformation]' + '--use-registry-identity-for-scm[look up source control dependencies in the registry and use their registry identity when possible to help deduplicate across the two origins]' + '--replace-scm-with-registry[look up source control dependencies in the registry and use the registry to retrieve them instead of source control when possible]' + '(--configuration -c)'{--configuration,-c}'[Build with configuration]:configuration:(debug release)' + '-Xcc[Pass flag through to all C compiler invocations]:Xcc:' + '-Xswiftc[Pass flag through to all Swift compiler invocations]:Xswiftc:' + '-Xlinker[Pass flag through to all linker invocations]:Xlinker:' + '-Xcxx[Pass flag through to all C++ compiler invocations]:Xcxx:' + '--triple:triple:' + '--sdk:sdk:_files -/' + '--toolchain:toolchain:_files -/' + '--sanitize[Turn on runtime checks for erroneous behavior, possible values: address, thread, undefined, scudo]:sanitize:' + '--auto-index-store[Enable or disable indexing-while-building feature]' + '--enable-index-store[Enable or disable indexing-while-building feature]' + '--disable-index-store[Enable or disable indexing-while-building feature]' + '--enable-parseable-module-interfaces' + '(--jobs -j)'{--jobs,-j}'[The number of jobs to spawn in parallel during the build process]:jobs:' + '--emit-swift-module-separately' + '--use-integrated-swift-driver' + '--experimental-explicit-module-build' + '--print-manifest-job-graph[Write the command graph for the build manifest as a graphviz file]' + '--build-system:build-system:(native xcode)' + '--enable-dead-strip[Disable/enable dead code stripping by the linker]' + '--disable-dead-strip[Disable/enable dead code stripping by the linker]' + '--static-swift-stdlib[Link Swift stdlib statically]' + '--no-static-swift-stdlib[Link Swift stdlib statically]' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' '(-): :->command' '(-)*:: :->arg' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 case $state in (command) - local modes - modes=( - 'completion-tool:Completion tool (for shell completions)' - 'dump-package:Print parsed Package.swift as JSON' - 'describe:Describe the current package' + local subcommands + subcommands=( 'clean:Delete build artifacts' - 'show-dependencies:Print the resolved dependency graph' - 'init:Initialize a new package' - 'unedit:Remove a package from editable mode' - 'tools-version:Manipulate tools version of the current package' - 'fetch:' - 'resolve:Resolve package dependencies' + 'purge-cache:Purge the global repository cache.' 'reset:Reset the complete cache/build directory' - 'generate-xcodeproj:Generates an Xcode project' - 'edit:Put a package in editable mode' - 'config:Manipulate configuration of the package' 'update:Update package dependencies' + 'describe:Describe the current package' + 'init:Initialize a new package' + '_format:' + 'diagnose-api-breaking-changes:Diagnose API-breaking changes to Swift modules in a package' + 'experimental-api-diff:Deprecated - use `swift package diagnose-api-breaking-changes` instead' + 'dump-symbol-graph:Dump Symbol Graph' + 'dump-pif:' + 'dump-package:Print parsed Package.swift as JSON' + 'edit:Put a package in editable mode' + 'unedit:Remove a package from editable mode' + 'config:Manipulate configuration of the package' + 'resolve:Resolve package dependencies' + 'fetch:' + 'show-dependencies:Print the resolved dependency graph' + 'tools-version:Manipulate tools version of the current package' + 'generate-xcodeproj:Generates an Xcode project. This command will be deprecated soon.' + 'compute-checksum:Compute the checksum for a binary artifact.' + 'archive-source:Create a source archive for the package' + 'completion-tool:Completion tool (for shell completions)' + 'plugin:Invoke a command plugin or perform other actions on command plugins' + 'default-command:' ) - _describe "mode" modes + _describe "subcommand" subcommands ;; (arg) case ${words[1]} in - (completion-tool) - _swift_package_completion-tool - ;; - (dump-package) - _swift_package_dump-package - ;; - (describe) - _swift_package_describe - ;; (clean) _swift_package_clean ;; - (show-dependencies) - _swift_package_show-dependencies - ;; - (init) - _swift_package_init - ;; - (unedit) - _swift_package_unedit - ;; - (tools-version) - _swift_package_tools-version - ;; - (fetch) - _swift_package_fetch - ;; - (resolve) - _swift_package_resolve + (purge-cache) + _swift_package_purge-cache ;; (reset) _swift_package_reset ;; - (generate-xcodeproj) - _swift_package_generate-xcodeproj + (update) + _swift_package_update + ;; + (describe) + _swift_package_describe + ;; + (init) + _swift_package_init + ;; + (_format) + _swift_package__format + ;; + (diagnose-api-breaking-changes) + _swift_package_diagnose-api-breaking-changes + ;; + (experimental-api-diff) + _swift_package_experimental-api-diff + ;; + (dump-symbol-graph) + _swift_package_dump-symbol-graph + ;; + (dump-pif) + _swift_package_dump-pif + ;; + (dump-package) + _swift_package_dump-package ;; (edit) _swift_package_edit ;; + (unedit) + _swift_package_unedit + ;; (config) _swift_package_config ;; - (update) - _swift_package_update + (resolve) + _swift_package_resolve + ;; + (fetch) + _swift_package_fetch + ;; + (show-dependencies) + _swift_package_show-dependencies + ;; + (tools-version) + _swift_package_tools-version + ;; + (generate-xcodeproj) + _swift_package_generate-xcodeproj + ;; + (compute-checksum) + _swift_package_compute-checksum + ;; + (archive-source) + _swift_package_archive-source + ;; + (completion-tool) + _swift_package_completion-tool + ;; + (plugin) + _swift_package_plugin + ;; + (default-command) + _swift_package_default-command ;; esac ;; esac -} -_swift_package_completion-tool() { - arguments=( - ": :{_values '' 'generate-bash-script[generate Bash completion script]' 'generate-zsh-script[generate Bash completion script]' 'list-dependencies[list all dependencies' names]' 'list-executables[list all executables' names]'}" - ) - _arguments $arguments && return -} - -_swift_package_dump-package() { - arguments=( - ) - _arguments $arguments && return -} - -_swift_package_describe() { - arguments=( - "--type[json|text]: :{_values '' 'text[describe using text format]' 'json[describe using JSON format]'}" - ) - _arguments $arguments && return + return ret } _swift_package_clean() { - arguments=( + integer ret=1 + local -a args + args+=( + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 + + return ret } -_swift_package_show-dependencies() { - arguments=( - "--format[text|dot|json|flatlist]: :{_values '' 'text[list dependencies using text format]' 'dot[list dependencies using dot format]' 'json[list dependencies using JSON format]'}" +_swift_package_purge-cache() { + integer ret=1 + local -a args + args+=( + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' ) - _arguments $arguments && return -} + _arguments -w -s -S $args[@] && ret=0 -_swift_package_init() { - arguments=( - "--type[empty|library|executable|system-module|manifest]: :{_values '' 'empty[generates an empty project]' 'library[generates project for a dynamic library]' 'executable[generates a project for a cli executable]' 'system-module[generates a project for a system module]'}" - "--name[Provide custom package name]:Provide custom package name: " - ) - _arguments $arguments && return -} - -_swift_package_unedit() { - arguments=( - ":The name of the package to unedit:_swift_dependency" - "--force[Unedit the package even if it has uncommited and unpushed changes.]" - ) - _arguments $arguments && return -} - -_swift_package_tools-version() { - arguments=( - "--set[Set tools version of package to the given value]:Set tools version of package to the given value: " - "--set-current[Set tools version of package to the current tools version in use]" - ) - _arguments $arguments && return -} - -_swift_package_fetch() { - arguments=( - ) - _arguments $arguments && return -} - -_swift_package_resolve() { - arguments=( - ":The name of the package to resolve:_swift_dependency" - "--version[The version to resolve at]:The version to resolve at: " - "--branch[The branch to resolve at]:The branch to resolve at: " - "--revision[The revision to resolve at]:The revision to resolve at: " - ) - _arguments $arguments && return + return ret } _swift_package_reset() { - arguments=( + integer ret=1 + local -a args + args+=( + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 + + return ret } -_swift_package_generate-xcodeproj() { - arguments=( - "--xcconfig-overrides[Path to xcconfig file]:Path to xcconfig file:_files" - "--enable-code-coverage[Enable code coverage in the generated project]" - "--output[Path where the Xcode project should be generated]:Path where the Xcode project should be generated:_files" - "--legacy-scheme-generator[Use the legacy scheme generator]" - "--watch[Watch for changes to the Package manifest to regenerate the Xcode project]" - "--skip-extra-files[Do not add file references for extra files to the generated Xcode project]" +_swift_package_update() { + integer ret=1 + local -a args + args+=( + '(--dry-run -n)'{--dry-run,-n}'[Display the list of dependencies that can be updated]' + ':packages:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_describe() { + integer ret=1 + local -a args + args+=( + '--type[json | text]:type:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_init() { + integer ret=1 + local -a args + args+=( + '--type[Package type: empty | library | executable | system-module | manifest]:type:' + '--name[Provide custom package name]:name:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package__format() { + integer ret=1 + local -a args + args+=( + ':swift-format-flags:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_diagnose-api-breaking-changes() { + integer ret=1 + local -a args + args+=( + '--breakage-allowlist-path[The path to a text file containing breaking changes which should be ignored by the API comparison. Each ignored breaking change in the file should appear on its own line and contain the exact message to be ignored (e.g. '"'"'API breakage: func foo() has been removed'"'"').]:breakage-allowlist-path:_files -/' + ':treeish:' + '--products[One or more products to include in the API comparison. If present, only the specified products (and any targets specified using `--targets`) will be compared.]:products:' + '--targets[One or more targets to include in the API comparison. If present, only the specified targets (and any products specified using `--products`) will be compared.]:targets:' + '--baseline-dir[The path to a directory used to store API baseline files. If unspecified, a temporary directory will be used.]:baseline-dir:_files -/' + '--regenerate-baseline[Regenerate the API baseline, even if an existing one is available.]' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_experimental-api-diff() { + integer ret=1 + local -a args + args+=( + ':args:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_dump-symbol-graph() { + integer ret=1 + local -a args + args+=( + '--pretty-print[Pretty-print the output JSON.]' + '--skip-synthesized-members[Skip members inherited through classes or default implementations.]' + '--minimum-access-level[Include symbols with this access level or more. Possible values: private | fileprivate | internal | public | open]:minimum-access-level:(private fileprivate internal public open)' + '--skip-inherited-docs[Skip emitting doc comments for members inherited through classes or default implementations.]' + '--include-spi-symbols[Add symbols with SPI information to the symbol graph.]' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_dump-pif() { + integer ret=1 + local -a args + args+=( + '--preserve-structure[Preserve the internal structure of PIF]' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_dump-package() { + integer ret=1 + local -a args + args+=( + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret } _swift_package_edit() { - arguments=( - ":The name of the package to edit:_swift_dependency" - "--revision[The revision to edit]:The revision to edit: " - "--branch[The branch to create]:The branch to create: " - "--path[Create or use the checkout at this path]:Create or use the checkout at this path:_files" + integer ret=1 + local -a args + args+=( + '--revision[The revision to edit]:revision:' + '--branch[The branch to create]:branch:' + '--path[Create or use the checkout at this path]:path:_files -/' + ':package-name:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_unedit() { + integer ret=1 + local -a args + args+=( + '--force[Unedit the package even if it has uncommitted and unpushed changes]' + ':package-name:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret } _swift_package_config() { - arguments=( + integer ret=1 + local -a args + args+=( + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' '(-): :->command' '(-)*:: :->arg' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 case $state in (command) - local modes - modes=( + local subcommands + subcommands=( + 'set-mirror:Set a mirror for a dependency' 'unset-mirror:Remove an existing mirror' 'get-mirror:Print mirror configuration for the given package dependency' - 'set-mirror:Set a mirror for a dependency' ) - _describe "mode" modes + _describe "subcommand" subcommands ;; (arg) case ${words[1]} in + (set-mirror) + _swift_package_config_set-mirror + ;; (unset-mirror) _swift_package_config_unset-mirror ;; (get-mirror) _swift_package_config_get-mirror ;; - (set-mirror) - _swift_package_config_set-mirror - ;; esac ;; esac -} -_swift_package_config_unset-mirror() { - arguments=( - "--package-url[The package dependency url]:The package dependency url: " - "--mirror-url[The mirror url]:The mirror url: " - ) - _arguments $arguments && return -} - -_swift_package_config_get-mirror() { - arguments=( - "--package-url[The package dependency url]:The package dependency url: " - ) - _arguments $arguments && return + return ret } _swift_package_config_set-mirror() { - arguments=( - "--package-url[The package dependency url]:The package dependency url: " - "--mirror-url[The mirror url]:The mirror url: " + integer ret=1 + local -a args + args+=( + '--package-url[The package dependency url]:package-url:' + '--original-url[The original url]:original-url:' + '--mirror-url[The mirror url]:mirror-url:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 + + return ret } -_swift_package_update() { - arguments=( +_swift_package_config_unset-mirror() { + integer ret=1 + local -a args + args+=( + '--package-url[The package dependency url]:package-url:' + '--original-url[The original url]:original-url:' + '--mirror-url[The mirror url]:mirror-url:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 + + return ret } -# Generates completions for swift test -# -# In the final compdef file, set the following file header: -# -# #compdef _swift_test -# local context state state_descr line -# typeset -A opt_args -_swift_test() { - arguments=( - "-Xcc[Pass flag through to all C compiler invocations]:Pass flag through to all C compiler invocations: " - "-Xswiftc[Pass flag through to all Swift compiler invocations]:Pass flag through to all Swift compiler invocations: " - "-Xlinker[Pass flag through to all linker invocations]:Pass flag through to all linker invocations: " - "-Xcxx[Pass flag through to all C++ compiler invocations]:Pass flag through to all C++ compiler invocations: " - "(--configuration -c)"{--configuration,-c}"[Build with configuration (debug|release) ]: :{_values '' 'debug[build with DEBUG configuration]' 'release[build with RELEASE configuration]'}" - "--build-path[Specify build/cache directory ]:Specify build/cache directory :_files" - "(--chdir -C)"{--chdir,-C}"[]: :_files" - "--package-path[Change working directory before any other operation]:Change working directory before any other operation:_files" - "--sanitize[Turn on runtime checks for erroneous behavior]: :{_values '' 'address[enable Address sanitizer]' 'thread[enable Thread sanitizer]' 'undefined[enable Undefined Behavior sanitizer]'}" - "--disable-prefetching[]" - "--skip-update[Skip updating dependencies from their remote during a resolution]" - "--disable-sandbox[Disable using the sandbox when executing subprocesses]" - "--disable-package-manifest-caching[Disable caching Package.swift manifests]" - "--version[]" - "--destination[]: :_files" - "(--verbose -v)"{--verbose,-v}"[Increase verbosity of informational output]" - "--no-static-swift-stdlib[Do not link Swift stdlib statically \[default\]]" - "--static-swift-stdlib[Link Swift stdlib statically]" - "--force-resolved-versions[]" - "--disable-automatic-resolution[Disable automatic resolution if Package.resolved file is out-of-date]" - "--enable-index-store[Enable indexing-while-building feature]" - "--disable-index-store[Disable indexing-while-building feature]" - "--enable-pubgrub-resolver[\[Experimental\] Enable the new Pubgrub dependency resolver]" - "--enable-parseable-module-interfaces[]" - "--trace-resolver[]" - "(--jobs -j)"{--jobs,-j}"[The number of jobs to spawn in parallel during the build process]:The number of jobs to spawn in parallel during the build process: " - "--enable-test-discovery[Enable test discovery on platforms without Objective-C runtime]" - "--skip-build[Skip building the test target]" - "(--list-tests -l)"{--list-tests,-l}"[Lists test methods in specifier format]" - "--generate-linuxmain[Generate LinuxMain.swift entries for the package]" - "--parallel[Run the tests in parallel.]" - "--num-workers[Number of tests to execute in parallel.]:Number of tests to execute in parallel.: " - "(--specifier -s)"{--specifier,-s}"[]: : " - "--xunit-output[]: :_files" - "--filter[Run test cases matching regular expression, Format: . or ./]:Run test cases matching regular expression, Format: . or ./: " - "--enable-code-coverage[Test with code coverage enabled]" +_swift_package_config_get-mirror() { + integer ret=1 + local -a args + args+=( + '--package-url[The package dependency url]:package-url:' + '--original-url[The original url]:original-url:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' ) - _arguments $arguments && return + _arguments -w -s -S $args[@] && ret=0 + + return ret } -_swift_compiler() { +_swift_package_resolve() { + integer ret=1 + local -a args + args+=( + '--version[The version to resolve at]:version:' + '--branch[The branch to resolve at]:branch:' + '--revision[The revision to resolve at]:revision:' + ':package-name:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_fetch() { + integer ret=1 + local -a args + args+=( + '--version[The version to resolve at]:version:' + '--branch[The branch to resolve at]:branch:' + '--revision[The revision to resolve at]:revision:' + ':package-name:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_show-dependencies() { + integer ret=1 + local -a args + args+=( + '--format[text | dot | json | flatlist]:format:' + '(--output-path -o)'{--output-path,-o}'[The absolute or relative path to output the resolved dependency graph.]:output-path:_files -/' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_tools-version() { + integer ret=1 + local -a args + args+=( + '--set-current[Set tools version of package to the current tools version in use]' + '--set[Set tools version of package to the given value]:set:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_generate-xcodeproj() { + integer ret=1 + local -a args + args+=( + '--xcconfig-overrides[Path to xcconfig file]:xcconfig-overrides:_files' + '--output[Path where the Xcode project should be generated]:output:_files -/' + '--legacy-scheme-generator[Use the legacy scheme generator]' + '--watch[Watch for changes to the Package manifest to regenerate the Xcode project]' + '--skip-extra-files[Do not add file references for extra files to the generated Xcode project]' + '--enable-code-coverage[Enable code coverage]' + '--disable-code-coverage[Enable code coverage]' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_compute-checksum() { + integer ret=1 + local -a args + args+=( + ':path:_files -/' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_archive-source() { + integer ret=1 + local -a args + args+=( + '(-o --output)'{-o,--output}'[The absolute or relative path for the generated source archive]:output:_files -/' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_completion-tool() { + integer ret=1 + local -a args + args+=( + ':mode:(generate-bash-script generate-zsh-script generate-fish-script list-dependencies list-executables list-snippets)' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_plugin() { + integer ret=1 + local -a args + args+=( + '--list[List the available command plugins]' + '--allow-writing-to-package-directory[Allow the plugin to write to the package directory]' + '--allow-writing-to-directory[Allow the plugin to write to an additional directory]:allow-writing-to-directory:' + ':command:' + ':arguments:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_package_default-command() { + integer ret=1 + local -a args + args+=( + '--allow-writing-to-package-directory[Allow the plugin to write to the package directory]' + '--allow-writing-to-directory[Allow the plugin to write to an additional directory]:allow-writing-to-directory:' + ':remaining:' + '--version[Show the version.]' + '(-help -h --help)'{-help,-h,--help}'[Show help information.]' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + +_swift_help() { + integer ret=1 + local -a args + args+=( + ':subcommands:' + ) + _arguments -w -s -S $args[@] && ret=0 + + return ret +} + + +_custom_completion() { + local completions=("${(@f)$($*)}") + _describe '' completions } _swift diff --git a/plugins/systemadmin/README.md b/plugins/systemadmin/README.md index 146b58605..3a9d9de66 100644 --- a/plugins/systemadmin/README.md +++ b/plugins/systemadmin/README.md @@ -41,7 +41,7 @@ plugins=(... systemadmin) | accessip10 | List the top 10 accesses to the ip address in the nginx/access.log file or another log file if specified | | visitpage20 | List the top 20 most visited files or pages in the nginx/access.log file or another log file if specified | | consume100 | List the 100 most time-consuming Page lists (more than 60 seconds) as well as the corresponding number of occurrences | -| webtraffic | List website traffic statistics in GB from tne nginx/access.log file or another log file if specified | +| webtraffic | List website traffic statistics in GB from the nginx/access.log file or another log file if specified | | c404 | List statistics on 404 connections in the nginx/access.log file or another log file if specified | | httpstatus | List statistics based on http status in the nginx/access.log file or another log file if specified | | d0 | Delete 0 byte files recursively in the current directory or another if specified | diff --git a/plugins/systemadmin/systemadmin.plugin.zsh b/plugins/systemadmin/systemadmin.plugin.zsh index 8e5e0af71..03dd995b6 100644 --- a/plugins/systemadmin/systemadmin.plugin.zsh +++ b/plugins/systemadmin/systemadmin.plugin.zsh @@ -13,11 +13,11 @@ # ------------------------------------------------------------------------------ function retlog() { - if [[ -z $1 ]];then - echo '/var/log/nginx/access.log' - else - echo $1 - fi + if [[ -z $1 ]];then + echo '/var/log/nginx/access.log' + else + echo $1 + fi } alias ping='ping -c 5' @@ -28,128 +28,160 @@ alias mkdir='mkdir -pv' alias psmem='ps -e -orss=,args= | sort -b -k1 -nr' alias psmem10='ps -e -orss=,args= | sort -b -k1 -nr | head -n 10' # get top process eating cpu if not work try execute : export LC_ALL='C' -alias pscpu='ps -e -o pcpu,cpu,nice,state,cputime,args|sort -k1,1n -nr' -alias pscpu10='ps -e -o pcpu,cpu,nice,state,cputime,args|sort -k1,1n -nr | head -n 10' +alias pscpu='ps -e -o pcpu,cpu,nice,state,cputime,args | sort -k1,1n -nr' +alias pscpu10='ps -e -o pcpu,cpu,nice,state,cputime,args | sort -k1,1n -nr | head -n 10' # top10 of the history alias hist10='print -l ${(o)history%% *} | uniq -c | sort -nr | head -n 10' +function ip() { + if [ -t 1 ]; then + command ip -color "$@" + else + command ip "$@" + fi +} + # directory LS function dls() { - print -l *(/) + print -l *(/) } function psgrep() { - ps aux | grep "${1:-.}" | grep -v grep + ps aux | grep "${1:-.}" | grep -v grep } # Kills any process that matches a regexp passed to it function killit() { - ps aux | grep -v "grep" | grep "$@" | awk '{print $2}' | xargs sudo kill + ps aux | grep -v "grep" | grep "$@" | awk '{print $2}' | xargs sudo kill } # list contents of directories in a tree-like format if ! (( $+commands[tree] )); then - function tree() { - find $@ -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g' - } + function tree() { + find $@ -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g' + } fi # Sort connection state function sortcons() { - netstat -nat |awk '{print $6}'|sort|uniq -c|sort -rn + { + LANG= ss -nat | awk 'NR > 1 {print $1}' \ + || LANG= netstat -nat | awk 'NR > 2 {print $6}' + } | sort | uniq -c | sort -rn } # View all 80 Port Connections function con80() { - netstat -nat|grep -i ":80"|wc -l + { + LANG= ss -nat || LANG= netstat -nat + } | grep -E ":80[^0-9]" | wc -l } # On the connected IP sorted by the number of connections function sortconip() { - netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -n + { + LANG= ss -ntu | awk 'NR > 1 {print $6}' \ + || LANG= netstat -ntu | awk 'NR > 2 {print $5}' + } | cut -d: -f1 | sort | uniq -c | sort -n } # top20 of Find the number of requests on 80 port function req20() { - netstat -anlp|grep 80|grep tcp|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n20 + { + LANG= ss -tn | awk '$4 ~ /:80$/ {print $5}' \ + || LANG= netstat -tn | awk '$4 ~ /:80$/ {print $5}' + } | awk -F: '{print $1}' | sort | uniq -c | sort -nr | head -n 20 } # top20 of Using tcpdump port 80 access to view function http20() { - sudo tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." '{print $1"."$2"."$3"."$4}' | sort | uniq -c | sort -nr |head -n 20 + sudo tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." '{print $1"."$2"."$3"."$4}' | sort | uniq -c | sort -nr | head -n 20 } # top20 of Find time_wait connection function timewait20() { - netstat -n|grep TIME_WAIT|awk '{print $5}'|sort|uniq -c|sort -rn|head -n20 + { + LANG= ss -nat | awk 'NR > 1 && /TIME-WAIT/ {print $5}' \ + || LANG= netstat -nat | awk 'NR > 2 && /TIME_WAIT/ {print $5}' + } | sort | uniq -c | sort -rn | head -n 20 } # top20 of Find SYN connection function syn20() { - netstat -an | grep SYN | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr|head -n20 + { + LANG= ss -an | awk '/SYN/ {print $5}' \ + || LANG= netstat -an | awk '/SYN/ {print $5}' + } | awk -F: '{print $1}' | sort | uniq -c | sort -nr | head -n20 } # Printing process according to the port number function port_pro() { - netstat -ntlp | grep "${1:-.}" | awk '{print $7}' | cut -d/ -f1 + LANG= ss -ntlp | awk "NR > 1 && /:${1:-}/ {print \$6}" | sed 's/.*pid=\([^,]*\).*/\1/' \ + || LANG= netstat -ntlp | awk "NR > 2 && /:${1:-}/ {print \$7}" | cut -d/ -f1 } # top10 of gain access to the ip address function accessip10() { - awk '{counts[$(11)]+=1}; END {for(url in counts) print counts[url], url}' "$(retlog)" + awk '{counts[$(11)]+=1}; END {for(url in counts) print counts[url], url}' "$(retlog)" } # top20 of Most Visited file or page function visitpage20() { - awk '{print $11}' "$(retlog)"|sort|uniq -c|sort -nr|head -n 20 + awk '{print $11}' "$(retlog)" | sort | uniq -c | sort -nr | head -n 20 } # top100 of Page lists the most time-consuming (more than 60 seconds) as well as the corresponding page number of occurrences function consume100() { - awk '($NF > 60 && $7~/\.php/){print $7}' "$(retlog)" |sort -n|uniq -c|sort -nr|head -n 100 - # if django website or other website make by no suffix language - # awk '{print $7}' "$(retlog)" |sort -n|uniq -c|sort -nr|head -n 100 + awk '($NF > 60 && $7~/\.php/){print $7}' "$(retlog)" | sort -n | uniq -c | sort -nr | head -n 100 + # if django website or other website make by no suffix language + # awk '{print $7}' "$(retlog)" | sort -n | uniq -c | sort -nr | head -n 100 } # Website traffic statistics (G) function webtraffic() { - awk "{sum+=$10} END {print sum/1024/1024/1024}" "$(retlog)" + awk "{sum+=$10} END {print sum/1024/1024/1024}" "$(retlog)" } # Statistical connections 404 function c404() { - awk '($9 ~/404/)' "$(retlog)" | awk '{print $9,$7}' | sort + awk '($9 ~ /404/)' "$(retlog)" | awk '{print $9,$7}' | sort } # Statistical http status. function httpstatus() { - awk '{counts[$(9)]+=1}; END {for(code in counts) print code, counts[code]}' "$(retlog)" + awk '{counts[$(9)]+=1}; END {for(code in counts) print code, counts[code]}' "$(retlog)" } # Delete 0 byte file function d0() { - find "${1:-.}" -type f -size 0 -exec rm -rf {} \; + find "${1:-.}" -type f -size 0 -exec rm -rf {} \; } # gather external ip address function geteip() { - curl -s -S -4 https://icanhazip.com - curl -s -S -6 https://icanhazip.com + curl -s -S -4 https://icanhazip.com + + # handle case when there is no IPv6 external IP, which shows error + # curl: (7) Couldn't connect to server + curl -s -S -6 https://icanhazip.com 2>/dev/null + local ret=$? + (( ret == 7 )) && print -P -u2 "%F{red}error: no IPv6 route to host%f" + return $ret } # determine local IP address(es) function getip() { - if (( ${+commands[ip]} )); then - ip addr | awk '/inet /{print $2}' | command grep -v 127.0.0.1 - else - ifconfig | awk '/inet /{print $2}' | command grep -v 127.0.0.1 - fi + if (( ${+commands[ip]} )); then + ip addr | awk '/inet /{print $2}' | command grep -v 127.0.0.1 + else + ifconfig | awk '/inet /{print $2}' | command grep -v 127.0.0.1 + fi } # Clear zombie processes function clrz() { - ps -eal | awk '{ if ($2 == "Z") {print $4}}' | kill -9 + ps -eal | awk '{ if ($2 == "Z") {print $4}}' | kill -9 } # Second concurrent function conssec() { - awk '{if($9~/200|30|404/)COUNT[$4]++}END{for( a in COUNT) print a,COUNT[a]}' "$(retlog)"|sort -k 2 -nr|head -n10 + awk '{if($9~/200|30|404/)COUNT[$4]++}END{for( a in COUNT) print a,COUNT[a]}' "$(retlog)" | sort -k 2 -nr | head -n10 } diff --git a/plugins/systemd/README.md b/plugins/systemd/README.md index ffa0567a8..755c649a1 100644 --- a/plugins/systemd/README.md +++ b/plugins/systemd/README.md @@ -12,6 +12,7 @@ plugins=(... systemd) | Alias | Command | Description | |:-----------------------|:-----------------------------------|:-----------------------------------------------------------------| +| `sc-failed` | `systemctl --failed` | List failed systemd units | | `sc-list-units` | `systemctl list-units` | List all units systemd has in memory | | `sc-is-active` | `systemctl is-active` | Show whether a unit is active | | `sc-status` | `systemctl status` | Show terse runtime status information about one or more units | diff --git a/plugins/systemd/systemd.plugin.zsh b/plugins/systemd/systemd.plugin.zsh index 7afd2be58..382a57b29 100644 --- a/plugins/systemd/systemd.plugin.zsh +++ b/plugins/systemd/systemd.plugin.zsh @@ -93,6 +93,9 @@ alias scu-enable-now="scu-enable --now" alias scu-disable-now="scu-disable --now" alias scu-mask-now="scu-mask --now" +# --failed commands +alias scu-failed='systemctl --user --failed' +alias sc-failed='systemctl --failed' function systemd_prompt_info { local unit @@ -107,6 +110,8 @@ function systemd_prompt_info { if systemctl is-active "$unit" &>/dev/null; then echo -n "$ZSH_THEME_SYSTEMD_PROMPT_ACTIVE" + elif systemctl --user is-active "$unit" &>/dev/null; then + echo -n "$ZSH_THEME_SYSTEMD_PROMPT_ACTIVE" else echo -n "$ZSH_THEME_SYSTEMD_PROMPT_NOTACTIVE" fi diff --git a/plugins/term_tab/README b/plugins/term_tab/README deleted file mode 100644 index 316062e73..000000000 --- a/plugins/term_tab/README +++ /dev/null @@ -1,16 +0,0 @@ - -term_tab - 'cwd' for all open zsh sessions -****************************************** - -What it does: -************* -This plugin allows to complete the 'cwd' of other Zsh sessions. Sounds -complicated but is rather simple. E.g. if you have three zsh sessions open, in -each session you are in a different folder, you can hit Ctrl+v in one session -to show you the current working directory of the other open zsh sessions. - -How it works: -************* -* It uses 'pidof zsh' to determine all zsh PIDs -* It reads procfs to get the current working directory of this session -* Everything is fed into zsh's completion magic diff --git a/plugins/term_tab/README.md b/plugins/term_tab/README.md new file mode 100644 index 000000000..59462a825 --- /dev/null +++ b/plugins/term_tab/README.md @@ -0,0 +1,18 @@ +# term_tab plugin + +This plugin only works for Solaris and linux. + +term_tab - `cwd` for all open zsh sessions + +## What it does: + +This plugin allows to complete the `cwd` of other Zsh sessions. Sounds +complicated but is rather simple. E.g. if you have three zsh sessions open, in +each session you are in a different folder, you can hit `Ctrl+V` in one session +to show you the current working directory of the other open zsh sessions. + +## How it works: + +* It uses `pidof zsh` to determine all zsh PIDs +* It reads procfs to get the current working directory of this session +* Everything is fed into zsh's completion magic diff --git a/plugins/term_tab/term_tab.plugin.zsh b/plugins/term_tab/term_tab.plugin.zsh index 1b612df68..89acd9103 100644 --- a/plugins/term_tab/term_tab.plugin.zsh +++ b/plugins/term_tab/term_tab.plugin.zsh @@ -28,6 +28,7 @@ function _term_list(){ case $OSTYPE in solaris*) dirs=( ${(M)${${(f)"$(pgrep -U $UID -x zsh|xargs pwdx)"}:#$$:*}%%/*} ) ;; linux*) dirs=( /proc/${^$(pidof zsh):#$$}/cwd(N:A) ) ;; + darwin*) dirs=( $( lsof -d cwd -c zsh -a -w -Fn | sed -n 's/^n//p' ) ) ;; esac dirs=( ${(D)dirs} ) diff --git a/plugins/terraform/README.md b/plugins/terraform/README.md index 59c6e7f2a..fc9a9f005 100644 --- a/plugins/terraform/README.md +++ b/plugins/terraform/README.md @@ -1,7 +1,7 @@ # Terraform plugin -Plugin for Terraform, a tool from Hashicorp for managing infrastructure safely and efficiently. -It adds completion for `terraform`, as well as aliases and a prompt function. +Plugin for Terraform, a tool from Hashicorp for managing infrastructure safely and efficiently. It adds +completion for `terraform`, as well as aliases and a prompt function. To use it, add `terraform` to the plugins array of your `~/.zshrc` file: @@ -11,7 +11,7 @@ plugins=(... terraform) ## Requirements -* [Terraform](https://terraform.io/) +- [Terraform](https://terraform.io/) ## Aliases @@ -19,6 +19,7 @@ plugins=(... terraform) | ----- | -------------------- | | `tf` | `terraform` | | `tfa` | `terraform apply` | +| `tfc` | `terraform console` | | `tfd` | `terraform destroy` | | `tff` | `terraform fmt` | | `tfi` | `terraform init` | @@ -28,11 +29,12 @@ plugins=(... terraform) ## Prompt function -You can add the current Terraform workspace in your prompt by adding `$(tf_prompt_info)` -to your `PROMPT` or `RPROMPT` variable. +You can add the current Terraform workspace in your prompt by adding `$(tf_prompt_info)`, +`$(tf_version_prompt_info)` to your `PROMPT` or `RPROMPT` variable. ```sh RPROMPT='$(tf_prompt_info)' +RPROMPT='$(tf_version_prompt_info)' ``` You can also specify the PREFIX and SUFFIX for the workspace with the following variables: @@ -40,4 +42,6 @@ You can also specify the PREFIX and SUFFIX for the workspace with the following ```sh ZSH_THEME_TF_PROMPT_PREFIX="%{$fg[white]%}" ZSH_THEME_TF_PROMPT_SUFFIX="%{$reset_color%}" +ZSH_THEME_TF_VERSION_PROMPT_PREFIX="%{$fg[white]%}" +ZSH_THEME_TF_VERSION_PROMPT_SUFFIX="%{$reset_color%}" ``` diff --git a/plugins/terraform/_terraform b/plugins/terraform/_terraform index a19e50670..625834563 100644 --- a/plugins/terraform/_terraform +++ b/plugins/terraform/_terraform @@ -47,7 +47,7 @@ __apply() { '-lock=[(true) Lock the state file when locking is supported.]:lock:(true false)' \ '-lock-timeout=[(0s) Duration to retry a state lock.]' \ '-input=[(true) Ask for input for variables if not directly set.]' \ - '-no-color[If specified, output wil be colorless.]' \ + '-no-color[If specified, output will be colorless.]' \ '-parallelism=[(10) Limit the number of parallel resource operations.]' \ '-refresh=[(true) Update state prior to checking for differences. This has no effect if a plan file is given to apply.]' \ '-state=[(terraform.tfstate) Path to read and save state (unless state-out is specified).]:statefile:_files -g "*.tfstate"' \ diff --git a/plugins/terraform/terraform.plugin.zsh b/plugins/terraform/terraform.plugin.zsh index d9e39e6ac..ccca54684 100644 --- a/plugins/terraform/terraform.plugin.zsh +++ b/plugins/terraform/terraform.plugin.zsh @@ -8,8 +8,16 @@ function tf_prompt_info() { echo "${ZSH_THEME_TF_PROMPT_PREFIX-[}${workspace:gs/%/%%}${ZSH_THEME_TF_PROMPT_SUFFIX-]}" } +function tf_version_prompt_info() { + local terraform_version + terraform_version=$(terraform --version | head -n 1 | cut -d ' ' -f 2) + echo "${ZSH_THEME_TF_VERSION_PROMPT_PREFIX-[}${terraform_version:gs/%/%%}${ZSH_THEME_TF_VERSION_PROMPT_SUFFIX-]}" +} + + alias tf='terraform' alias tfa='terraform apply' +alias tfc='terraform console' alias tfd='terraform destroy' alias tff='terraform fmt' alias tfi='terraform init' diff --git a/plugins/tig/tig.plugin.zsh b/plugins/tig/tig.plugin.zsh index 7e0c530ac..5b7d2550a 100644 --- a/plugins/tig/tig.plugin.zsh +++ b/plugins/tig/tig.plugin.zsh @@ -1,3 +1,5 @@ alias tis='tig status' alias til='tig log' alias tib='tig blame -C' +alias tif='tig reflog' +alias tia='tig --all' diff --git a/plugins/tmux/README.md b/plugins/tmux/README.md index 7348f77c9..b4516ef26 100644 --- a/plugins/tmux/README.md +++ b/plugins/tmux/README.md @@ -25,19 +25,20 @@ The plugin also supports the following: | `tkss` | tmux kill-session -t | Terminate named running tmux session | | `tmux` | `_zsh_tmux_plugin_run` | Start a new tmux session | | `tmuxconf` | `$EDITOR $ZSH_TMUX_CONFIG` | Open .tmux.conf file with an editor | +| `tds` | `_tmux_directory_session` | Creates or attaches to a session for the current path | ## Configuration Variables -| Variable | Description | -| ----------------------------------- | ----------------------------------------------------------------------------- | -| `ZSH_TMUX_AUTOSTART` | Automatically starts tmux (default: `false`) | -| `ZSH_TMUX_AUTOSTART_ONCE` | Autostart only if tmux hasn't been started previously (default: `true`) | -| `ZSH_TMUX_AUTOCONNECT` | Automatically connect to a previous session if it exits (default: `true`) | -| `ZSH_TMUX_AUTOQUIT` | Automatically closes terminal once tmux exits (default: `ZSH_TMUX_AUTOSTART`) | -| `ZSH_TMUX_FIXTERM` | Sets `$TERM` to 256-color term or not based on current terminal support | -| `ZSH_TMUX_ITERM2` | Sets the `-CC` option for iTerm2 tmux integration (default: `false`) | -| `ZSH_TMUX_FIXTERM_WITHOUT_256COLOR` | `$TERM` to use for non 256-color terminals (default: `screen`) | -| `ZSH_TMUX_FIXTERM_WITH_256COLOR` | `$TERM` to use for 256-color terminals (default: `screen-256color` | -| `ZSH_TMUX_CONFIG` | Set the configuration path (default: `$HOME/.tmux.conf`) | -| `ZSH_TMUX_UNICODE` | Set `tmux -u` option to support unicode | -| `ZSH_TMUX_DEFAULT_SESSION_NAME` | Set tmux default session name when autostart is enabled | +| Variable | Description | +| ----------------------------------- | ------------------------------------------------------------------------------------------- | +| `ZSH_TMUX_AUTOSTART` | Automatically starts tmux (default: `false`) | +| `ZSH_TMUX_AUTOSTART_ONCE` | Autostart only if tmux hasn't been started previously (default: `true`) | +| `ZSH_TMUX_AUTOCONNECT` | Automatically connect to a previous session if it exits (default: `true`) | +| `ZSH_TMUX_AUTOQUIT` | Automatically closes terminal once tmux exits (default: `ZSH_TMUX_AUTOSTART`) | +| `ZSH_TMUX_FIXTERM` | Sets `$TERM` to 256-color term or not based on current terminal support | +| `ZSH_TMUX_ITERM2` | Sets the `-CC` option for iTerm2 tmux integration (default: `false`) | +| `ZSH_TMUX_FIXTERM_WITHOUT_256COLOR` | `$TERM` to use for non 256-color terminals (default: `screen`) | +| `ZSH_TMUX_FIXTERM_WITH_256COLOR` | `$TERM` to use for 256-color terminals (default: `screen-256color` | +| `ZSH_TMUX_CONFIG` | Set the configuration path (default: `$HOME/.tmux.conf`, `$XDG_CONFIG_HOME/tmux/tmux.conf`) | +| `ZSH_TMUX_UNICODE` | Set `tmux -u` option to support unicode | +| `ZSH_TMUX_DEFAULT_SESSION_NAME` | Set tmux default session name when autostart is enabled | diff --git a/plugins/tmux/tmux.plugin.zsh b/plugins/tmux/tmux.plugin.zsh index b9bb66d59..72cdd4818 100644 --- a/plugins/tmux/tmux.plugin.zsh +++ b/plugins/tmux/tmux.plugin.zsh @@ -26,12 +26,17 @@ fi # systems without the proper terminfo : ${ZSH_TMUX_FIXTERM_WITH_256COLOR:=screen-256color} # Set the configuration path -: ${ZSH_TMUX_CONFIG:=$HOME/.tmux.conf} +if [[ -e $HOME/.tmux.conf ]]; then + : ${ZSH_TMUX_CONFIG:=$HOME/.tmux.conf} +elif [[ -e ${XDG_CONFIG_HOME:-$HOME/.config}/tmux/tmux.conf ]]; then + : ${ZSH_TMUX_CONFIG:=${XDG_CONFIG_HOME:-$HOME/.config}/tmux/tmux.conf} +else + : ${ZSH_TMUX_CONFIG:=$HOME/.tmux.conf} +fi # Set -u option to support unicode : ${ZSH_TMUX_UNICODE:=false} # ALIASES - alias ta='tmux attach -t' alias tad='tmux attach -d -t' alias ts='tmux new-session -s' @@ -73,7 +78,11 @@ function _zsh_tmux_plugin_run() { [[ "$ZSH_TMUX_UNICODE" == "true" ]] && tmux_cmd+=(-u) # Try to connect to an existing session. - [[ "$ZSH_TMUX_AUTOCONNECT" == "true" ]] && $tmux_cmd attach + if [[ -n "$ZSH_TMUX_DEFAULT_SESSION_NAME" ]]; then + [[ "$ZSH_TMUX_AUTOCONNECT" == "true" ]] && $tmux_cmd attach -t $ZSH_TMUX_DEFAULT_SESSION_NAME + else + [[ "$ZSH_TMUX_AUTOCONNECT" == "true" ]] && $tmux_cmd attach + fi # If failed, just run tmux, fixing the TERM variable if requested. if [[ $? -ne 0 ]]; then @@ -83,9 +92,9 @@ function _zsh_tmux_plugin_run() { tmux_cmd+=(-f "$ZSH_TMUX_CONFIG") fi if [[ -n "$ZSH_TMUX_DEFAULT_SESSION_NAME" ]]; then - $tmux_cmd new-session -s $ZSH_TMUX_DEFAULT_SESSION_NAME + $tmux_cmd new-session -s $ZSH_TMUX_DEFAULT_SESSION_NAME else - $tmux_cmd new-session + $tmux_cmd new-session fi fi @@ -99,8 +108,21 @@ compdef _tmux _zsh_tmux_plugin_run # Alias tmux to our wrapper function. alias tmux=_zsh_tmux_plugin_run +function _tmux_directory_session() { + # current directory without leading path + local dir=${PWD##*/} + # md5 hash for the full working directory path + local md5=$(printf '%s' "$PWD" | md5sum | cut -d ' ' -f 1) + # human friendly unique session name for this directory + local session_name="${dir}-${md5:0:6}" + # create or attach to the session + tmux new -As "$session_name" +} + +alias tds=_tmux_directory_session + # Autostart if not already in tmux and enabled. -if [[ -z "$TMUX" && "$ZSH_TMUX_AUTOSTART" == "true" && -z "$INSIDE_EMACS" && -z "$EMACS" && -z "$VIM" ]]; then +if [[ -z "$TMUX" && "$ZSH_TMUX_AUTOSTART" == "true" && -z "$INSIDE_EMACS" && -z "$EMACS" && -z "$VIM" && -z "$INTELLIJ_ENVIRONMENT_READER" ]]; then # Actually don't autostart if we already did and multiple autostarts are disabled. if [[ "$ZSH_TMUX_AUTOSTART_ONCE" == "false" || "$ZSH_TMUX_AUTOSTARTED" != "true" ]]; then export ZSH_TMUX_AUTOSTARTED=true diff --git a/plugins/toolbox/README.md b/plugins/toolbox/README.md index abaca31f4..bc04a906b 100644 --- a/plugins/toolbox/README.md +++ b/plugins/toolbox/README.md @@ -22,4 +22,5 @@ RPROMPT='$(toolbox_prompt_info)' | Alias | Command | Description | |-------|----------------------|----------------------------------------| -| tb | `toolbox enter` | Enters the toolbox environment | +| tbe | `toolbox enter` | Enters the toolbox environment | +| tbr | `toolbox run` | Run a command in an existing toolbox | diff --git a/plugins/toolbox/toolbox.plugin.zsh b/plugins/toolbox/toolbox.plugin.zsh index d24d6d396..377e498cd 100644 --- a/plugins/toolbox/toolbox.plugin.zsh +++ b/plugins/toolbox/toolbox.plugin.zsh @@ -2,4 +2,5 @@ function toolbox_prompt_info() { [[ -f /run/.toolboxenv ]] && echo "⬢" } -alias tb="toolbox enter" +alias tbe="toolbox enter" +alias tbr="toolbox run" diff --git a/plugins/vi-mode/README.md b/plugins/vi-mode/README.md index 476666bf6..84ba30105 100644 --- a/plugins/vi-mode/README.md +++ b/plugins/vi-mode/README.md @@ -29,12 +29,16 @@ plugins=(... vi-mode) VI_MODE_SET_CURSOR=true ``` + See [Cursor Styles](#cursor-styles) for controlling how the cursor looks in different modes + - `MODE_INDICATOR`: controls the string displayed when the shell is in normal mode. See [Mode indicators](#mode-indicators) for details. - `INSERT_MODE_INDICATOR`: controls the string displayed when the shell is in insert mode. See [Mode indicators](#mode-indicators) for details. +- `VI_MODE_DISABLE_CLIPBOARD`: If set, disables clipboard integration on yank/paste + ## Mode indicators *Normal mode* is indicated with a red `<<<` mark at the right prompt, when it @@ -49,8 +53,42 @@ MODE_INDICATOR="%F{white}+%f" INSERT_MODE_INDICATOR="%F{yellow}+%f" ``` -You can also use the `vi_mode_prompt_info` function in your prompt, which will display -this mode indicator. +### Adding mode indicators to your prompt + +`Vi-mode` by default will add mode indicators to `RPROMPT` **unless** that is defined by +a preceding plugin. + +If `PROMPT` or `RPROMPT` is not defined to your liking, you can add mode info manually. The `vi_mode_prompt_info` function is available to insert mode indicator information. + +Here are some examples: + +```bash +source $ZSH/oh-my-zsh.sh + +PROMPT="$PROMPT\$(vi_mode_prompt_info)" +RPROMPT="\$(vi_mode_prompt_info)$RPROMPT" +``` + +Note the `\$` here, which importantly prevents interpolation at the time of defining, but allows it to be executed for each prompt update event. + +## Cursor Styles + +You can control the cursor style used in each active vim mode by changing the values of the following variables. + +```zsh +# defaults +VI_MODE_CURSOR_NORMAL=2 +VI_MODE_CURSOR_VISUAL=6 +VI_MODE_CURSOR_INSERT=6 +VI_MODE_CURSOR_OPPEND=0 +``` + +- 0, 1 - Blinking block +- 2 - Solid block +- 3 - Blinking underline +- 4 - Solid underline +- 5 - Blinking line +- 6 - Solid line ## Key bindings @@ -108,11 +146,17 @@ NOTE: this used to be bound to `v`. That is now the default (`visual-mode`). - `c{motion}` : Delete {motion} text and start insert - `cc` : Delete line and start insert - `C` : Delete to the end of the line and start insert +- `P` : Insert the contents of the clipboard before the cursor +- `p` : Insert the contents of the clipboard after the cursor - `r{char}` : Replace the character under the cursor with {char} - `R` : Enter replace mode: Each character replaces existing one - `x` : Delete `count` characters under and after the cursor - `X` : Delete `count` characters before the cursor +NOTE: delete/kill commands (`dd`, `D`, `c{motion}`, `C`, `x`,`X`) and yank commands +(`y`, `Y`) will copy to the clipboard. Contents can then be put back using paste commands +(`P`, `p`). + ## Known issues ### Low `$KEYTIMEOUT` diff --git a/plugins/vi-mode/vi-mode.plugin.zsh b/plugins/vi-mode/vi-mode.plugin.zsh index 149d6bbd5..5c104f7bb 100644 --- a/plugins/vi-mode/vi-mode.plugin.zsh +++ b/plugins/vi-mode/vi-mode.plugin.zsh @@ -14,6 +14,15 @@ typeset -g VI_MODE_RESET_PROMPT_ON_MODE_CHANGE # Unset or set to any other value to do the opposite. typeset -g VI_MODE_SET_CURSOR +# Control how the cursor appears in the various vim modes. This only applies +# if $VI_MODE_SET_CURSOR=true. +# +# See https://vt100.net/docs/vt510-rm/DECSCUSR for cursor styles +typeset -g VI_MODE_CURSOR_NORMAL=2 +typeset -g VI_MODE_CURSOR_VISUAL=6 +typeset -g VI_MODE_CURSOR_INSERT=6 +typeset -g VI_MODE_CURSOR_OPPEND=0 + typeset -g VI_KEYMAP=main function _vi-mode-set-cursor-shape-for-keymap() { @@ -22,24 +31,44 @@ function _vi-mode-set-cursor-shape-for-keymap() { # https://vt100.net/docs/vt510-rm/DECSCUSR local _shape=0 case "${1:-${VI_KEYMAP:-main}}" in - main) _shape=6 ;; # vi insert: line - viins) _shape=6 ;; # vi insert: line - isearch) _shape=6 ;; # inc search: line - command) _shape=6 ;; # read a command name - vicmd) _shape=2 ;; # vi cmd: block - visual) _shape=2 ;; # vi visual mode: block - viopp) _shape=0 ;; # vi operation pending: blinking block + main) _shape=$VI_MODE_CURSOR_INSERT ;; # vi insert: line + viins) _shape=$VI_MODE_CURSOR_INSERT ;; # vi insert: line + isearch) _shape=$VI_MODE_CURSOR_INSERT ;; # inc search: line + command) _shape=$VI_MODE_CURSOR_INSERT ;; # read a command name + vicmd) _shape=$VI_MODE_CURSOR_NORMAL ;; # vi cmd: block + visual) _shape=$VI_MODE_CURSOR_VISUAL ;; # vi visual mode: block + viopp) _shape=$VI_MODE_CURSOR_OPPEND ;; # vi operation pending: blinking block *) _shape=0 ;; esac printf $'\e[%d q' "${_shape}" } +function _visual-mode { + typeset -g VI_KEYMAP=visual + _vi-mode-set-cursor-shape-for-keymap "$VI_KEYMAP" + zle .visual-mode +} +zle -N visual-mode _visual-mode + +function _vi-mode-should-reset-prompt() { + # If $VI_MODE_RESET_PROMPT_ON_MODE_CHANGE is unset (default), dynamically + # check whether we're using the prompt to display vi-mode info + if [[ -z "${VI_MODE_RESET_PROMPT_ON_MODE_CHANGE:-}" ]]; then + [[ "${PS1} ${RPS1}" = *'$(vi_mode_prompt_info)'* ]] + return $? + fi + + # If $VI_MODE_RESET_PROMPT_ON_MODE_CHANGE was manually set, let's check + # if it was specifically set to true or it was disabled with any other value + [[ "${VI_MODE_RESET_PROMPT_ON_MODE_CHANGE}" = true ]] +} + # Updates editor information when the keymap changes. function zle-keymap-select() { # update keymap variable for the prompt typeset -g VI_KEYMAP=$KEYMAP - if [[ "${VI_MODE_RESET_PROMPT_ON_MODE_CHANGE:-}" = true ]]; then + if _vi-mode-should-reset-prompt; then zle reset-prompt zle -R fi @@ -50,10 +79,9 @@ zle -N zle-keymap-select # These "echoti" statements were originally set in lib/key-bindings.zsh # Not sure the best way to extend without overriding. function zle-line-init() { - local prev_vi_keymap - prev_vi_keymap="${VI_KEYMAP:-}" + local prev_vi_keymap="${VI_KEYMAP:-}" typeset -g VI_KEYMAP=main - [[ "$prev_vi_keymap" != 'main' ]] && [[ "${VI_MODE_RESET_PROMPT_ON_MODE_CHANGE:-}" = true ]] && zle reset-prompt + [[ "$prev_vi_keymap" != 'main' ]] && _vi-mode-should-reset-prompt && zle reset-prompt (( ! ${+terminfo[smkx]} )) || echoti smkx _vi-mode-set-cursor-shape-for-keymap "${VI_KEYMAP}" } @@ -119,9 +147,19 @@ function wrap_clipboard_widgets() { done } -wrap_clipboard_widgets copy vi-yank vi-yank-eol vi-backward-kill-word vi-change-whole-line vi-delete vi-delete-char -wrap_clipboard_widgets paste vi-put-{before,after} -unfunction wrap_clipboard_widgets +if [[ -z "${VI_MODE_DISABLE_CLIPBOARD:-}" ]]; then + wrap_clipboard_widgets copy \ + vi-yank vi-yank-eol vi-yank-whole-line \ + vi-change vi-change-eol vi-change-whole-line \ + vi-kill-line vi-kill-eol vi-backward-kill-word \ + vi-delete vi-delete-char vi-backward-delete-char + + wrap_clipboard_widgets paste \ + vi-put-{before,after} \ + put-replace-selection + + unfunction wrap_clipboard_widgets +fi # if mode indicator wasn't setup by theme, define default, we'll leave INSERT_MODE_INDICATOR empty by default if [[ -z "$MODE_INDICATOR" ]]; then @@ -129,13 +167,6 @@ if [[ -z "$MODE_INDICATOR" ]]; then fi function vi_mode_prompt_info() { - # If we're using the prompt to display mode info, and we haven't explicitly - # disabled "reset prompt on mode change", then set it here. - # - # We do that here instead of the `if` statement below because the user may - # set RPS1/RPROMPT to something else in their custom config. - : "${VI_MODE_RESET_PROMPT_ON_MODE_CHANGE:=true}" - echo "${${VI_KEYMAP/vicmd/$MODE_INDICATOR}/(main|viins)/$INSERT_MODE_INDICATOR}" } diff --git a/plugins/vscode/README.md b/plugins/vscode/README.md index e95ed5d4f..726b23d35 100644 --- a/plugins/vscode/README.md +++ b/plugins/vscode/README.md @@ -31,7 +31,7 @@ the Command Palette via (F1 or ⇧⌘P) and type shell command to find the Shell ## Using multiple flavours -If for any reason, you ever require to use multiple flavours of VS Code i.e. VS Code (stable) and VS Code Insiders, you can +If for any reason, you ever require to use multiple flavours of VS Code i.e. VS Code (stable) and VS Code Insiders, you can manually specify the flavour's executable. Add the following line to the .zshrc file (between the `ZSH_THEME` and the `plugins=()` lines). This will make the plugin use your manually defined executable. @@ -53,6 +53,7 @@ source $ZSH/oh-my-zsh.sh | Alias | Command | Description | | ----------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------- | | vsc | code . | Open the current folder in VS code | +| vsc `dir` | code `dir` | Open passed folder in VS code | | vsca `dir` | code --add `dir` | Add folder(s) to the last active window | | vscd `file` `file` | code --diff `file` `file` | Compare two files with each other. | | vscg `file:line[:char]` | code --goto `file:line[:char]` | Open a file at the path on the specified line and character position. | diff --git a/plugins/vscode/vscode.plugin.zsh b/plugins/vscode/vscode.plugin.zsh index 48d904377..356c62360 100644 --- a/plugins/vscode/vscode.plugin.zsh +++ b/plugins/vscode/vscode.plugin.zsh @@ -23,7 +23,14 @@ if [[ -z "$VSCODE" ]]; then fi fi -alias vsc="$VSCODE ." +function vsc { + if (( $# )); then + $VSCODE $@ + else + $VSCODE . + fi +} + alias vsca="$VSCODE --add" alias vscd="$VSCODE --diff" alias vscg="$VSCODE --goto" diff --git a/plugins/watson/README.md b/plugins/watson/README.md new file mode 100644 index 000000000..ef734ec63 --- /dev/null +++ b/plugins/watson/README.md @@ -0,0 +1,9 @@ +# Watson + +This plugin provides completion for [Watson](https://tailordev.github.io/Watson/). + +To use it add `watson` to the plugins array in your zshrc file. + +```zsh +plugins=(... watson) +``` diff --git a/plugins/watson/_watson b/plugins/watson/_watson new file mode 100644 index 000000000..0f599bd66 --- /dev/null +++ b/plugins/watson/_watson @@ -0,0 +1,34 @@ +#compdef watson + +_watson_completion() { + local -a completions + local -a completions_with_descriptions + local -a response + (( ! $+commands[watson] )) && return 1 + + response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) _WATSON_COMPLETE=zsh_complete watson)}") + + for type key descr in ${response}; do + if [[ "$type" == "plain" ]]; then + if [[ "$descr" == "_" ]]; then + completions+=("$key") + else + completions_with_descriptions+=("$key":"$descr") + fi + elif [[ "$type" == "dir" ]]; then + _path_files -/ + elif [[ "$type" == "file" ]]; then + _path_files -f + fi + done + + if [ -n "$completions_with_descriptions" ]; then + _describe -V unsorted completions_with_descriptions -U + fi + + if [ -n "$completions" ]; then + compadd -U -V unsorted -a completions + fi +} + +compdef _watson_completion watson; diff --git a/plugins/wd/README.md b/plugins/wd/README.md index 8791f9f0e..1d1980632 100644 --- a/plugins/wd/README.md +++ b/plugins/wd/README.md @@ -1,12 +1,12 @@ # wd -[![Build Status](https://travis-ci.org/mfaerevaag/wd.png?branch=master)](https://travis-ci.org/mfaerevaag/wd) +[![Build Status](https://github.com/mfaerevaag/wd/actions/workflows/test.yml/badge.svg)](https://github.com/mfaerevaag/wd/actions) `wd` (*warp directory*) lets you jump to custom directories in zsh, without using `cd`. Why? Because `cd` seems inefficient when the folder is frequently visited or has a long path. -![tty.gif](https://raw.githubusercontent.com/mfaerevaag/wd/master/tty.gif) +![Demo](https://raw.githubusercontent.com/mfaerevaag/wd/master/tty.gif) ## Setup @@ -36,6 +36,10 @@ In your `.zshrc`: antibody bundle mfaerevaag/wd ``` +### [Fig](https://fig.io) + +Install `wd` here: [![Fig plugin store](https://fig.io/badges/install-with-fig.svg)](https://fig.io/plugins/other/wd_mfaerevaag) + ### Arch ([AUR](https://aur.archlinux.org/packages/zsh-plugin-wd-git/)) 1. Install from the AUR diff --git a/plugins/wd/wd.sh b/plugins/wd/wd.sh index 9085c5b7b..840e92d61 100644 --- a/plugins/wd/wd.sh +++ b/plugins/wd/wd.sh @@ -163,6 +163,7 @@ wd_add() { local point=$1 local force=$2 + cmdnames=(add rm show list ls path clean help) if [[ $point == "" ]] then @@ -178,6 +179,9 @@ wd_add() elif [[ $point =~ : ]] || [[ $point =~ / ]] then wd_exit_fail "Warp point contains illegal character (:/)" + elif (($cmdnames[(Ie)$point])) + then + wd_exit_fail "Warp point name cannot be a wd command (see wd -h for a full list)" elif [[ ${points[$point]} == "" ]] || [ ! -z "$force" ] then wd_remove "$point" > /dev/null @@ -185,7 +189,7 @@ wd_add() if (whence sort >/dev/null); then local config_tmp=$(mktemp "${TMPDIR:-/tmp}/wd.XXXXXXXXXX") # use 'cat' below to ensure we respect $WD_CONFIG as a symlink - command sort -o "${config_tmp}" "$WD_CONFIG" && command cat "${config_tmp}" > "$WD_CONFIG" && command rm "${config_tmp}" + command sort -o "${config_tmp}" "$WD_CONFIG" && command cat "${config_tmp}" >| "$WD_CONFIG" && command rm "${config_tmp}" fi wd_export_static_named_directories @@ -214,7 +218,7 @@ wd_remove() then local config_tmp=$(mktemp "${TMPDIR:-/tmp}/wd.XXXXXXXXXX") # Copy and delete in two steps in order to preserve symlinks - if sed -n "/^${point_name}:.*$/!p" "$WD_CONFIG" > "$config_tmp" && command cp "$config_tmp" "$WD_CONFIG" && command rm "$config_tmp" + if sed -n "/^${point_name}:.*$/!p" "$WD_CONFIG" >| "$config_tmp" && command cp "$config_tmp" "$WD_CONFIG" && command rm "$config_tmp" then wd_print_msg "$WD_GREEN" "Warp point removed" else @@ -251,7 +255,7 @@ wd_list_all() then arr=(${(s,:,)line}) key=${arr[1]} - val=${arr[2]} + val=${line#"${arr[1]}:"} if [[ -z $wd_quiet_mode ]] then @@ -389,6 +393,11 @@ else wd_export_static_named_directories fi +# disable extendedglob for the complete wd execution time +setopt | grep -q extendedglob +wd_extglob_is_set=$? +(( ! $wd_extglob_is_set )) && setopt noextendedglob + # load warp points typeset -A points while read -r line @@ -475,6 +484,9 @@ fi # if not, next time warp will pick up variables from this run # remember, there's no sub shell +(( ! $wd_extglob_is_set )) && setopt extendedglob + +unset wd_extglob_is_set unset wd_warp unset wd_add unset wd_remove diff --git a/plugins/web-search/README.md b/plugins/web-search/README.md index da90f90a0..6e4b4d7b8 100644 --- a/plugins/web-search/README.md +++ b/plugins/web-search/README.md @@ -12,8 +12,8 @@ plugins=( ... web-search) You can use the `web-search` plugin in these two forms: -* `web_search [more terms if you want]` -* ` [more terms if you want]` +- `web_search [more terms if you want]` +- ` [more terms if you want]` For example, these two are equivalent: @@ -24,41 +24,42 @@ $ google oh-my-zsh Available search contexts are: -| Context | URL | -|-----------------------|------------------------------------------| -| `bing` | `https://www.bing.com/search?q=` | -| `google` | `https://www.google.com/search?q=` | -| `yahoo` | `https://search.yahoo.com/search?p=` | -| `ddg` or `duckduckgo` | `https://www.duckduckgo.com/?q=` | -| `sp` or `startpage` | `https://www.startpage.com/do/search?q=` | -| `yandex` | `https://yandex.ru/yandsearch?text=` | -| `github` | `https://github.com/search?q=` | -| `baidu` | `https://www.baidu.com/s?wd=` | -| `ecosia` | `https://www.ecosia.org/search?q=` | -| `goodreads` | `https://www.goodreads.com/search?q=` | -| `qwant` | `https://www.qwant.com/?q=` | -| `givero` | `https://www.givero.com/search?q=` | -| `stackoverflow` | `https://stackoverflow.com/search?q=` | -| `wolframalpha` | `https://wolframalpha.com/input?i=` | -| `archive` | `https://web.archive.org/web/*/` | -| `scholar` | `https://scholar.google.com/scholar?q=` | +| Context | URL | +| --------------------- | ----------------------------------------------- | +| `bing` | `https://www.bing.com/search?q=` | +| `google` | `https://www.google.com/search?q=` | +| `brs` or `brave` | `https://search.brave.com/search?q=` | +| `yahoo` | `https://search.yahoo.com/search?p=` | +| `ddg` or `duckduckgo` | `https://www.duckduckgo.com/?q=` | +| `sp` or `startpage` | `https://www.startpage.com/do/search?q=` | +| `yandex` | `https://yandex.ru/yandsearch?text=` | +| `github` | `https://github.com/search?q=` | +| `baidu` | `https://www.baidu.com/s?wd=` | +| `ecosia` | `https://www.ecosia.org/search?q=` | +| `goodreads` | `https://www.goodreads.com/search?q=` | +| `qwant` | `https://www.qwant.com/?q=` | +| `givero` | `https://www.givero.com/search?q=` | +| `stackoverflow` | `https://stackoverflow.com/search?q=` | +| `wolframalpha` | `https://wolframalpha.com/input?i=` | +| `archive` | `https://web.archive.org/web/*/` | +| `scholar` | `https://scholar.google.com/scholar?q=` | +| `ask` | `https://www.ask.com/web?q=` | +| `youtube` | `https://www.youtube.com/results?search_query=` | Also there are aliases for bang-searching DuckDuckGo: | Context | Bang | -|-----------|-------| +| --------- | ----- | | `wiki` | `!w` | | `news` | `!n` | -| `youtube` | `!yt` | | `map` | `!m` | | `image` | `!i` | | `ducky` | `!` | ### Custom search engines -If you want to add other search contexts to the plugin, you can use the -`$ZSH_WEB_SEARCH_ENGINES` variable. Set it before Oh My Zsh is sourced, -with the following format: +If you want to add other search contexts to the plugin, you can use the `$ZSH_WEB_SEARCH_ENGINES` variable. +Set it before Oh My Zsh is sourced, with the following format: ```zsh ZSH_WEB_SEARCH_ENGINES=( @@ -67,13 +68,12 @@ ZSH_WEB_SEARCH_ENGINES=( ) ``` -where `` is the name of the search context, and `` a URL of -the same type as the search contexts above. For example, to add `reddit`, -you'd do: +where `` is the name of the search context, and `` a URL of the same type as the search contexts +above. For example, to add `reddit`, you'd do: ```zsh ZSH_WEB_SEARCH_ENGINES=(reddit "https://www.reddit.com/search/?q=") ``` -These custom search engines will also be turned to aliases, so you can -both do `web_search reddit ` or `reddit `. +These custom search engines will also be turned to aliases, so you can both do `web_search reddit ` or +`reddit `. diff --git a/plugins/web-search/web-search.plugin.zsh b/plugins/web-search/web-search.plugin.zsh index 229948894..a8848fd95 100644 --- a/plugins/web-search/web-search.plugin.zsh +++ b/plugins/web-search/web-search.plugin.zsh @@ -7,22 +7,25 @@ function web_search() { typeset -A urls urls=( $ZSH_WEB_SEARCH_ENGINES - google "https://www.google.com/search?q=" - bing "https://www.bing.com/search?q=" - yahoo "https://search.yahoo.com/search?p=" - duckduckgo "https://www.duckduckgo.com/?q=" - startpage "https://www.startpage.com/do/search?q=" - yandex "https://yandex.ru/yandsearch?text=" - github "https://github.com/search?q=" - baidu "https://www.baidu.com/s?wd=" - ecosia "https://www.ecosia.org/search?q=" - goodreads "https://www.goodreads.com/search?q=" - qwant "https://www.qwant.com/?q=" - givero "https://www.givero.com/search?q=" - stackoverflow "https://stackoverflow.com/search?q=" - wolframalpha "https://www.wolframalpha.com/input/?i=" - archive "https://web.archive.org/web/*/" - scholar "https://scholar.google.com/scholar?q=" + google "https://www.google.com/search?q=" + bing "https://www.bing.com/search?q=" + brave "https://search.brave.com/search?q=" + yahoo "https://search.yahoo.com/search?p=" + duckduckgo "https://www.duckduckgo.com/?q=" + startpage "https://www.startpage.com/do/search?q=" + yandex "https://yandex.ru/yandsearch?text=" + github "https://github.com/search?q=" + baidu "https://www.baidu.com/s?wd=" + ecosia "https://www.ecosia.org/search?q=" + goodreads "https://www.goodreads.com/search?q=" + qwant "https://www.qwant.com/?q=" + givero "https://www.givero.com/search?q=" + stackoverflow "https://stackoverflow.com/search?q=" + wolframalpha "https://www.wolframalpha.com/input/?i=" + archive "https://web.archive.org/web/*/" + scholar "https://scholar.google.com/scholar?q=" + ask "https://www.ask.com/web?q=" + youtube "https://www.youtube.com/results?search_query=" ) # check whether the search engine is supported @@ -47,6 +50,7 @@ function web_search() { alias bing='web_search bing' +alias brs='web_search brave' alias google='web_search google' alias yahoo='web_search yahoo' alias ddg='web_search duckduckgo' @@ -62,11 +66,12 @@ alias stackoverflow='web_search stackoverflow' alias wolframalpha='web_search wolframalpha' alias archive='web_search archive' alias scholar='web_search scholar' +alias ask='web_search ask' +alias youtube='web_search youtube' #add your own !bang searches here alias wiki='web_search duckduckgo \!w' alias news='web_search duckduckgo \!n' -alias youtube='web_search duckduckgo \!yt' alias map='web_search duckduckgo \!m' alias image='web_search duckduckgo \!i' alias ducky='web_search duckduckgo \!' diff --git a/plugins/xcode/xcode.plugin.zsh b/plugins/xcode/xcode.plugin.zsh index 3bd12cdec..f09434e69 100644 --- a/plugins/xcode/xcode.plugin.zsh +++ b/plugins/xcode/xcode.plugin.zsh @@ -17,6 +17,13 @@ function xc { local active_path active_path=${"$(xcode-select -p)"%%/Contents/Developer*} echo "Found ${xcode_files[1]}. Opening with ${active_path}" + + # If Xcode is already opened in another Desk, we need this double call + # with -g to open the project window in the current Desk and focus it. + # See https://github.com/ohmyzsh/ohmyzsh/issues/10384 + if command pgrep -q "^Xcode"; then + open -g -a "$active_path" "${xcode_files[1]}" + fi open -a "$active_path" "${xcode_files[1]}" } @@ -31,7 +38,7 @@ function xx { open -a "Xcode.app" "$@" } -# "XCode-SELect by Version" - select Xcode by just version number +# "Xcode-Select by Version" - select Xcode by just version number # Uses naming convention: # - different versions of Xcode are named Xcode-.app or stored # in a folder named Xcode- diff --git a/plugins/yarn/README.md b/plugins/yarn/README.md index 9c16ff2c3..5c7c7f323 100644 --- a/plugins/yarn/README.md +++ b/plugins/yarn/README.md @@ -15,7 +15,7 @@ It also adds `yarn` global scripts dir (commonly `~/.yarn/bin`) to the `$PATH`. To disable this feature, set the following style in your `.zshrc`: ```zsh -zstyle ':omz:plugins:yarn' global-path false +zstyle ':omz:plugins:yarn' global-path no ``` ## Aliases @@ -29,6 +29,7 @@ zstyle ':omz:plugins:yarn' global-path false | yb | `yarn build` | Run the build script defined in `package.json` | | ycc | `yarn cache clean` | Clean yarn's global cache of packages | | yd | `yarn dev` | Run the dev script defined in `package.json` | +| yf | `yarn format` | Run the dev script defined in `package.json` | | yga | `yarn global add` | Install packages globally on your operating system | | ygls | `yarn global list` | Lists global installed packages | | ygrm | `yarn global remove` | Remove global installed packages from your OS | @@ -54,3 +55,4 @@ zstyle ':omz:plugins:yarn' global-path false | yv | `yarn version` | Update the version of your package | | yw | `yarn workspace` | Run a command within a single workspace. | | yws | `yarn workspaces` | Run a command within all defined workspaces. | +| yy | `yarn why` | Show why a package has been installed, detailing which other packages depend on it | diff --git a/plugins/yarn/_yarn b/plugins/yarn/_yarn index 1237ba672..f15756ff4 100644 --- a/plugins/yarn/_yarn +++ b/plugins/yarn/_yarn @@ -144,7 +144,7 @@ _yarn_scripts() { fi if [[ -n $packageJson ]]; then - scripts=("${(@f)$(cat ${packageJson} | perl -0777 -MJSON::PP -n -E '%r=%{decode_json($_)->{scripts}}; do{$k=$_;($e=$k)=~s/:/\\:/g; printf "$e:$r{$k}\n"} for sort keys %r')}") + scripts=("${(@f)$(cat ${packageJson} | perl -0777 -MJSON::PP -n -E 'binmode(STDOUT, ":encoding(UTF-8)"); %r=%{decode_json($_)->{scripts}}; do{$k=$_;($e=$k)=~s/:/\\:/g; printf "$e:$r{$k}\n"} for sort keys %r')}") fi commands=('env' $scripts $binaries) diff --git a/plugins/yarn/yarn.plugin.zsh b/plugins/yarn/yarn.plugin.zsh index bcb8661cf..157044d71 100644 --- a/plugins/yarn/yarn.plugin.zsh +++ b/plugins/yarn/yarn.plugin.zsh @@ -17,6 +17,7 @@ alias yap="yarn add --peer" alias yb="yarn build" alias ycc="yarn cache clean" alias yd="yarn dev" +alias yf="yarn format" alias yga="yarn global add" alias ygls="yarn global list" alias ygrm="yarn global remove" @@ -42,3 +43,4 @@ alias yup="yarn upgrade" alias yv="yarn version" alias yw="yarn workspace" alias yws="yarn workspaces" +alias yy="yarn why" diff --git a/plugins/z/LICENSE b/plugins/z/LICENSE new file mode 100644 index 000000000..6af13b9e0 --- /dev/null +++ b/plugins/z/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018-2023 Alexandros Kozak + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/z/MANUAL.md b/plugins/z/MANUAL.md new file mode 100644 index 000000000..67a207dbb --- /dev/null +++ b/plugins/z/MANUAL.md @@ -0,0 +1,366 @@ +# Zsh-z + +[![MIT License](img/mit_license.svg)](https://opensource.org/licenses/MIT) +![Zsh version 4.3.11 and higher](img/zsh_4.3.11_plus.svg) +[![GitHub stars](https://img.shields.io/github/stars/agkozak/zsh-z.svg)](https://github.com/agkozak/zsh-z/stargazers) + +![Zsh-z demo](img/demo.gif) + +Zsh-z is a command line tool that allows you to jump quickly to directories that you have visited frequently in the past, or recently -- but most often a combination of the two (a concept known as ["frecency"](https://en.wikipedia.org/wiki/Frecency)). It works by keeping track of when you go to directories and how much time you spend in them. It is then in the position to guess where you want to go when you type a partial string, e.g., `z src` might take you to `~/src/zsh`. `z zsh` might also get you there, and `z c/z` might prove to be even more specific -- it all depends on your habits and how much time you have been using Zsh-z to build up a database. After using Zsh-z for a little while, you will get to where you want to be by typing considerably less than you would need if you were using `cd`. + +Zsh-z is a native Zsh port of [rupa/z](https://github.com/rupa/z), a tool written for `bash` and Zsh that uses embedded `awk` scripts to do the heavy lifting. It was quite possibly my most used command line tool for a couple of years. I decided to translate it, `awk` parts and all, into pure Zsh script, to see if by eliminating calls to external tools (`awk`, `sort`, `date`, `sed`, `mv`, `rm`, and `chown`) and reducing forking through subshells I could make it faster. The performance increase is impressive, particularly on systems where forking is slow, such as Cygwin, MSYS2, and WSL. I have found that, in those environments, switching directories using Zsh-z can be over 100% faster than it is using `rupa/z`. + +There is a noteworthy stability increase as well. Race conditions have always been a problem with `rupa/z`, and users of that utility will occasionally lose their `.z` databases. By having Zsh-z only use Zsh (`rupa/z` uses a hybrid shell code that works on `bash` as well), I have been able to implement a `zsh/system`-based file-locking mechanism similar to [the one @mafredri once proposed for `rupa/z`](https://github.com/rupa/z/pull/199). It is now nearly impossible to crash the database, even through extreme testing. + +There are other, smaller improvements which I try to document in [Improvements and Fixes](#improvements-and-fixes). These include the new default behavior of sorting your tab completions by frecency rather than just letting Zsh sort the raw results alphabetically (a behavior which can be restored if you like it -- [see below](#settings)). + +Zsh-z is a drop-in replacement for `rupa/z` and will, by default, use the same database (`~/.z`), so you can go on using `rupa/z` when you launch `bash`. + +## Table of Contents +- [News](#news) +- [Installation](#installation) +- [Command Line Options](#command-line-options) +- [Settings](#settings) +- [Case Sensitivity](#case-sensitivity) +- [`ZSHZ_UNCOMMON`](#zshz_uncommon) +- [Making `--add` work for you](#making---add-work-for-you) +- [Other Improvements and Fixes](#other-improvements-and-fixes) +- [Migrating from Other Tools](#migrating-from-other-tools) +- [`COMPLETE_ALIASES`](#complete_aliases) +- [Known Bugs](#known-bugs) + +## News + +
+ Here are the latest features and updates. + +- August 24, 2023 + + Zsh-z will now run when `setopt NO_UNSET` has been enabled (props @ntninja). +- August 23, 2023 + + Better logic for loading `zsh/files` (props @z0rc) +- August 2, 2023 + + Zsh-z still uses the `zsh/files` module when possible, but will fall back on the standard `chown`, `mv`, and `rm` commands in its absence. +- April 27, 2023 + + Zsh-z now allows the user to specify the directory-changing command using the `ZSHZ_CD` environment variable (default: `builtin cd`; props @basnijholt). +- January 27, 2023 + + If the datafile directory specified by `ZSHZ_DATA` or `_Z_DATA` does not already exist, create it (props @mattmc3). +- June 29, 2022 + + Zsh-z is less likely to leave temporary files sitting around (props @mafredri). +- June 27, 2022 + + A bug was fixed which was preventing paths with spaces in them from being updated ([#61](https://github.com/agkozak/zsh-z/issues/61)). + + If writing to the temporary database file fails, the database will not be clobbered (props @mafredri). +- December 19, 2021 + + ZSH-z will now display tildes for `HOME` during completion when `ZSHZ_TILDE=1` has been set. +- November 11, 2021 + + A bug was fixed which was preventing ranks from being incremented. + + `--add` has been made to work with relative paths and has been documented for the user. +- October 14, 2021 + + Completions were being sorted alphabetically, rather than by rank; this error has been fixed. +- September 25, 2021 + + Orthographical change: "Zsh," not "ZSH." +- September 23, 2021 + + `z -xR` will now remove a directory *and its subdirectories* from the database. + + `z -x` and `z -xR` can now take an argument; without one, `PWD` is assumed. +- September 7, 2021 + + Fixed the unload function so that it removes the `$ZSHZ_CMD` alias (default: `z`). +- August 27, 2021 + + Using `print -v ... -f` instead of `print -v` to work around longstanding bug in Zsh involving `print -v` and multibyte strings. +- August 13, 2021 + + Fixed the explanation string printed during completion so that it may be formatted with `zstyle`. + + Zsh-z now declares `ZSHZ_EXCLUDE_DIRS` as an array with unique elements so that you do not have to. +- July 29, 2021 + + Temporarily disabling use of `print -v`, which seems to be mangling CJK multibyte strings. +- July 27, 2021 + + Internal escaping of path names now works with older versions of ZSH. + + Zsh-z now detects and discards any incomplete or incorrectly formatted database entries. +- July 10, 2021 + + Setting `ZSHZ_TRAILING_SLASH=1` makes it so that a search pattern ending in `/` can match the end of a path; e.g. `z foo/` can match `/path/to/foo`. +- June 25, 2021 + + Setting `ZSHZ_TILDE=1` displays the `HOME` directory as `~`. +- May 7, 2021 + + Setting `ZSHZ_ECHO=1` will cause Zsh-z to display the new path when you change directories. + + Better escaping of path names to deal paths containing the characters ``\`()[]``. +- February 15, 2021 + + Ranks are displayed the way `rupa/z` now displays them, i.e. as large integers. This should help Zsh-z to integrate with other tools. +- January 31, 2021 + + Zsh-z is now efficient enough that, on MSYS2 and Cygwin, it is faster to run it in the foreground than it is to fork a subshell for it. + + `_zshz_precmd` simply returns if `PWD` is `HOME` or in `ZSH_EXCLUDE_DIRS`, rather than waiting for `zshz` to do that. +- January 17, 2021 + + Made sure that the `PUSHD_IGNORE_DUPS` option is respected. +- January 14, 2021 + + The `z -h` help text now breaks at spaces. + + `z -l` was not working for Zsh version < 5. +- January 11, 2021 + + Major refactoring of the code. + + `z -lr` and `z -lt` work as expected. + + `EXTENDED_GLOB` has been disabled within the plugin to accommodate old-fashioned Windows directories with names such as `Progra~1`. + + Removed `zshelldoc` documentation. +- January 6, 2021 + + I have corrected the frecency routine so that it matches `rupa/z`'s math, but for the present, Zsh-z will continue to display ranks as 1/10000th of what they are in `rupa/z` -- [they had to multiply theirs by 10000](https://github.com/rupa/z/commit/f1f113d9bae9effaef6b1e15853b5eeb445e0712) to work around `bash`'s inadequacies at dealing with decimal fractions. +- January 5, 2021 + + If you try `z foo`, and `foo` is not in the database but `${PWD}/foo` is a valid directory, Zsh-z will `cd` to it. +- December 22, 2020 + + `ZSHZ_CASE`: when set to `ignore`, pattern matching is case-insensitive; when set to `smart`, patterns are matched case-insensitively when they are all lowercase and case-sensitively when they have uppercase characters in them (a behavior very much like Vim's `smartcase` setting). + + `ZSHZ_KEEP_DIRS` is an array of directory names that should not be removed from the database, even if they are not currently available (useful when a drive is not always mounted). + + Symlinked datafiles were having their symlinks overwritten; this bug has been fixed. + +
+ +## Installation + +### General observations + +This plugin can be installed simply by putting the various files in a directory together and by sourcing `zsh-z.plugin.zsh` in your `.zshrc`: + + source /path/to/zsh-z.plugin.zsh + +For tab completion to work, `_zshz` *must* be in the same directory as `zsh-z.plugin.zsh`, and you will want to have loaded `compinit`. The frameworks handle this themselves. If you are not using a framework, put + + autoload -U compinit; compinit + +in your .zshrc somewhere below where you source `zsh-z.plugin.zsh`. + +If you add + + zstyle ':completion:*' menu select + +to your `.zshrc`, your completion menus will look very nice. This `zstyle` invocation should work with any of the frameworks below as well. + +### For [antigen](https://github.com/zsh-users/antigen) users + +Add the line + + antigen bundle agkozak/zsh-z + +to your `.zshrc`, somewhere above the line that says `antigen apply`. + +### For [Oh My Zsh](http://ohmyz.sh/) users + +Zsh-z is now included as part of Oh My Zsh! As long as you are using an up-to-date installation of Oh My Zsh, you can activate Zsh-z simply by adding `z` to your `plugins` array in your `.zshrc`, e.g., + + plugins=( git z ) + +It is as simple as that. + +If, however, you prefer always to use the latest version of Zsh-z from the `agkozak/zsh-z` repo, you may install it thus: + + git clone https://github.com/agkozak/zsh-z ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-z + +and activate it by adding `zsh-z` to the line of your `.zshrc` that specifies `plugins=()`, e.g., `plugins=( git zsh-z )`. + +### For [prezto](https://github.com/sorin-ionescu/prezto) users + +Execute the following command: + + git clone https://github.com/agkozak/zsh-z.git ~/.zprezto-contrib/zsh-z + +Then edit your `~/.zpreztorc` file. Make sure the line that says + + zstyle ':prezto:load' pmodule-dirs $HOME/.zprezto-contrib + +is uncommented. Then find the section that specifies which modules are to be loaded; it should look something like this: + + zstyle ':prezto:load' pmodule \ + 'environment' \ + 'terminal' \ + 'editor' \ + 'history' \ + 'directory' \ + 'spectrum' \ + 'utility' \ + 'completion' \ + 'prompt' + +Add a backslash to the end of the last line add `'zsh-z'` to the list, e.g., + + zstyle ':prezto:load' pmodule \ + 'environment' \ + 'terminal' \ + 'editor' \ + 'history' \ + 'directory' \ + 'spectrum' \ + 'utility' \ + 'completion' \ + 'prompt' \ + 'zsh-z' + +Then relaunch `zsh`. + +### For [zcomet](https://github.com/agkozak/zcomet) users + +Simply add + + zcomet load agkozak/zsh-z + +to your `.zshrc` (below where you source `zcomet.zsh` and above where you run `zcomet compinit`). + +### For [zgen](https://github.com/tarjoilija/zgen) users + +Add the line + + zgen load agkozak/zsh-z + +somewhere above the line that says `zgen save`. Then run + + zgen reset + zsh + +to refresh your init script. + +### For [Zim](https://github.com/zimfw/zimfw) + +Add the following line to your `.zimrc`: + + zmodule https://github.com/agkozak/zsh-z + +Then run + + zimfw install + +and restart your shell. + +### For [Zinit](https://github.com/zdharma-continuum/zinit) users + +Add the line + + zinit load agkozak/zsh-z + +to your `.zshrc`. + +`zsh-z` supports `zinit`'s `unload` feature; just run `zinit unload agkozak/zshz` to restore the shell to its state before `zsh-z` was loaded. + +### For [Znap](https://github.com/marlonrichert/zsh-snap) users + +Add the line + + znap source agkozak/zsh-z + +somewhere below the line where you `source` Znap itself. + +### For [zplug](https://github.com/zplug/zplug) users + +Add the line + + zplug "agkozak/zsh-z" + +somewhere above the line that says `zplug load`. Then run + + zplug install + zplug load + +to install `zsh-z`. + +## Command Line Options + +- `--add` Add a directory to the database +- `-c` Only match subdirectories of the current directory +- `-e` Echo the best match without going to it +- `-h` Display help +- `-l` List all matches without going to them +- `-r` Match by rank (i.e. how much time you spend in directories) +- `-t` Time -- match by how recently you have been to directories +- `-x` Remove a directory (by default, the current directory) from the database +- `-xR` Remove a directory (by default, the current directory) and its subdirectories from the database + +# Settings + +Zsh-z has environment variables (they all begin with `ZSHZ_`) that change its behavior if you set them; you can also keep your old ones if you have been using `rupa/z` (they begin with `_Z_`). + +* `ZSHZ_CMD` changes the command name (default: `z`) +* `ZSHZ_CD` specifies the default directory-changing command (default: `builtin cd`) +* `ZSHZ_COMPLETION` can be `'frecent'` (default) or `'legacy'`, depending on whether you want your completion results sorted according to frecency or simply sorted alphabetically +* `ZSHZ_DATA` changes the database file (default: `~/.z`) +* `ZSHZ_ECHO` displays the new path name when changing directories (default: `0`) +* `ZSHZ_EXCLUDE_DIRS` is an array of directories to keep out of the database (default: empty) +* `ZSHZ_KEEP_DIRS` is an array of directories that should not be removed from the database, even if they are not currently available (useful when a drive is not always mounted) (default: empty) +* `ZSHZ_MAX_SCORE` is the maximum combined score the database entries can have before they begin to age and potentially drop out of the database (default: 9000) +* `ZSHZ_NO_RESOLVE_SYMLINKS` prevents symlink resolution (default: `0`) +* `ZSHZ_OWNER` allows usage when in `sudo -s` mode (default: empty) +* `ZSHZ_TILDE` displays the name of the `HOME` directory as a `~` (default: `0`) +* `ZSHZ_TRAILING_SLASH` makes it so that a search pattern ending in `/` can match the final element in a path; e.g., `z foo/` can match `/path/to/foo` (default: `0`) +* `ZSHZ_UNCOMMON` changes the logic used to calculate the directory jumped to; [see below](#zshz_uncommon`) (default: `0`) + +## Case sensitivity + +The default behavior of Zsh-z is to try to find a case-sensitive match. If there is none, then Zsh-z tries to find a case-insensitive match. + +Some users prefer simple case-insensitivity; this behavior can be enabled by setting + + ZSHZ_CASE=ignore + +If you like Vim's `smartcase` setting, where lowercase patterns are case-insensitive while patterns with any uppercase characters are treated case-sensitively, try setting + + ZSHZ_CASE=smart + +## `ZSHZ_UNCOMMON` + +A common complaint about the default behavior of `rupa/z` and Zsh-z involves "common prefixes." If you type `z code` and the best matches, in increasing order, are + + /home/me/code/foo + /home/me/code/bar + /home/me/code/bat + +Zsh-z will see that all possible matches share a common prefix and will send you to that directory -- `/home/me/code` -- which is often a desirable result. But if the possible matches are + + /home/me/.vscode/foo + /home/me/code/foo + /home/me/code/bar + /home/me/code/bat + +then there is no common prefix. In this case, `z code` will simply send you to the highest-ranking match, `/home/me/code/bat`. + +You may enable an alternate, experimental behavior by setting `ZSHZ_UNCOMMON=1`. If you do that, Zsh-z will not jump to a common prefix, even if one exists. Instead, it chooses the highest-ranking match -- but it drops any subdirectories that do not include the search term. So if you type `z bat` and `/home/me/code/bat` is the best match, that is exactly where you will end up. If, however, you had typed `z code` and the best match was also `/home/me/code/bat`, you would have ended up in `/home/me/code` (because `code` was what you had searched for). This feature is still in development, and feedback is welcome. + +## Making `--add` Work for You + +Zsh-z internally uses the `--add` option to add paths to its database. @zachriggle pointed out to me that users might want to use `--add` themselves, so I have altered it a little to make it more user-friendly. + +A good example might involve a directory tree that has Git repositories within it. The working directories could be added to the Zsh-z database as a batch with + + for i in $(find $PWD -maxdepth 3 -name .git -type d); do + z --add ${i:h} + done + +(As a Zsh user, I tend to use `**` instead of `find`, but it is good to see how deep your directory trees go before doing that.) + + +## Other Improvements and Fixes + +* `z -x` works, with the help of `chpwd_functions`. +* Zsh-z works on Solaris. +* Zsh-z uses the "new" `zshcompsys` completion system instead of the old `compctl` one. +* There is no error message when the database file has not yet been created. +* There is support for special characters (e.g., `[`) in directory names. +* If `z -l` only returns one match, a common root is not printed. +* Exit status codes increasingly make sense. +* Completions work with options `-c`, `-r`, and `-t`. +* If `~/foo` and `~/foob` are matches, `~/foo` is *not* the common root. Only a common parent directory can be a common root. +* `z -x` and the new, recursive `z -xR` can take an argument so that you can remove directories other than `PWD` from the database. + +## Migrating from Other Tools + +Zsh-z's database format is identical to that of `rupa/z`. You may switch freely between the two tools (I still use `rupa/z` for `bash`). `fasd` also uses that database format, but it stores it by default in `~/.fasd`, so you will have to `cp ~/.fasd ~/.z` if you want to use your old directory history. + +If you are coming to Zsh-z (or even to the original `rupa/z`, for that matter) from `autojump`, try using my [`jumpstart-z`](https://github.com/agkozak/jumpstart-z/blob/master/jumpstart-z) tool to convert your old database to the Zsh-z format, or simply run + + awk -F "\t" '{printf("%s|%0.f|%s\n", $2, $1, '"$(date +%s)"')}' < /path/to/autojump.txt > ~/.z + +## `COMPLETE_ALIASES` + +`z`, or any alternative you set up using `$ZSH_CMD` or `$_Z_CMD`, is an alias. `setopt COMPLETE_ALIASES` divorces the tab completion for aliases from the underlying commands they invoke, so if you enable `COMPLETE_ALIASES`, tab completion for Zsh-z will be broken. You can get it working again, however, by adding under + + setopt COMPLETE_ALIASES + +the line + + compdef _zshz ${ZSHZ_CMD:-${_Z_CMD:-z}} + +That will re-bind `z` or the command of your choice to the underlying Zsh-z function. + +## Known Bugs +It is possible to run a completion on a string with spaces in it, e.g., `z us bi` might take you to `/usr/local/bin`. This works, but as things stand, after the completion the command line reads + + z us /usr/local/bin. + +You get where you want to go, but the detritus on the command line is annoying. This is also a problem in `rupa/z`, but I am keen on eventually eliminating this glitch. Advice is welcome. diff --git a/plugins/z/Makefile b/plugins/z/Makefile deleted file mode 100644 index dcf433d40..000000000 --- a/plugins/z/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -readme: - @groff -man -Tascii z.1 | col -bx - -.PHONY: readme diff --git a/plugins/z/README b/plugins/z/README deleted file mode 100644 index 47e54c57a..000000000 --- a/plugins/z/README +++ /dev/null @@ -1,148 +0,0 @@ -Z(1) User Commands Z(1) - - - -NAME - z - jump around - -SYNOPSIS - z [-chlrtx] [regex1 regex2 ... regexn] - -AVAILABILITY - bash, zsh - -DESCRIPTION - Tracks your most used directories, based on 'frecency'. - - After a short learning phase, z will take you to the most 'frecent' - directory that matches ALL of the regexes given on the command line, in - order. - - For example, z foo bar would match /foo/bar but not /bar/foo. - -OPTIONS - -c restrict matches to subdirectories of the current directory - - -e echo the best match, don't cd - - -h show a brief help message - - -l list only - - -r match by rank only - - -t match by recent access only - - -x remove the current directory from the datafile - -EXAMPLES - z foo cd to most frecent dir matching foo - - z foo bar cd to most frecent dir matching foo, then bar - - z -r foo cd to highest ranked dir matching foo - - z -t foo cd to most recently accessed dir matching foo - - z -l foo list all dirs matching foo (by frecency) - -NOTES - Installation: - Put something like this in your $HOME/.bashrc or $HOME/.zshrc: - - . /path/to/z.sh - - cd around for a while to build up the db. - - PROFIT!! - - Optionally: - Set $_Z_CMD to change the command name (default z). - Set $_Z_DATA to change the datafile (default $HOME/.z). - Set $_Z_MAX_SCORE lower to age entries out faster (default - 9000). - Set $_Z_NO_RESOLVE_SYMLINKS to prevent symlink resolution. - Set $_Z_NO_PROMPT_COMMAND to handle PROMPT_COMMAND/precmd your- - self. - Set $_Z_EXCLUDE_DIRS to an array of directory trees to exclude. - Set $_Z_OWNER to allow usage when in 'sudo -s' mode. - (These settings should go in .bashrc/.zshrc before the line - added above.) - Install the provided man page z.1 somewhere in your MANPATH, - like /usr/local/man/man1. - - Aging: - The rank of directories maintained by z undergoes aging based on a sim- - ple formula. The rank of each entry is incremented every time it is - accessed. When the sum of ranks is over 9000, all ranks are multiplied - by 0.99. Entries with a rank lower than 1 are forgotten. - - Frecency: - Frecency is a portmanteau of 'recent' and 'frequency'. It is a weighted - rank that depends on how often and how recently something occurred. As - far as I know, Mozilla came up with the term. - - To z, a directory that has low ranking but has been accessed recently - will quickly have higher rank than a directory accessed frequently a - long time ago. - - Frecency is determined at runtime. - - Common: - When multiple directories match all queries, and they all have a common - prefix, z will cd to the shortest matching directory, without regard to - priority. This has been in effect, if undocumented, for quite some - time, but should probably be configurable or reconsidered. - - Tab Completion: - z supports tab completion. After any number of arguments, press TAB to - complete on directories that match each argument. Due to limitations of - the completion implementations, only the last argument will be com- - pleted in the shell. - - Internally, z decides you've requested a completion if the last argu- - ment passed is an absolute path to an existing directory. This may - cause unexpected behavior if the last argument to z begins with /. - -ENVIRONMENT - A function _z() is defined. - - The contents of the variable $_Z_CMD is aliased to _z 2>&1. If not set, - $_Z_CMD defaults to z. - - The environment variable $_Z_DATA can be used to control the datafile - location. If it is not defined, the location defaults to $HOME/.z. - - The environment variable $_Z_NO_RESOLVE_SYMLINKS can be set to prevent - resolving of symlinks. If it is not set, symbolic links will be - resolved when added to the datafile. - - In bash, z appends a command to the PROMPT_COMMAND environment variable - to maintain its database. In zsh, z appends a function _z_precmd to the - precmd_functions array. - - The environment variable $_Z_NO_PROMPT_COMMAND can be set if you want - to handle PROMPT_COMMAND or precmd yourself. - - The environment variable $_Z_EXCLUDE_DIRS can be set to an array of - directory trees to exclude from tracking. $HOME is always excluded. - Directories must be full paths without trailing slashes. - - The environment variable $_Z_OWNER can be set to your username, to - allow usage of z when your sudo environment keeps $HOME set. - -FILES - Data is stored in $HOME/.z. This can be overridden by setting the - $_Z_DATA environment variable. When initialized, z will raise an error - if this path is a directory, and not function correctly. - - A man page (z.1) is provided. - -SEE ALSO - regex(7), pushd, popd, autojump, cdargs - - Please file bugs at https://github.com/rupa/z/ - - - -z January 2013 Z(1) diff --git a/plugins/z/README.md b/plugins/z/README.md index ea8d4610a..5b7d6f649 100644 --- a/plugins/z/README.md +++ b/plugins/z/README.md @@ -1,8 +1,9 @@ # z - jump around -This plugin defines the [z command](https://github.com/rupa/z) that tracks your most visited directories and allows you to access them with very few keystrokes. +This plugin defines the [z command](https://github.com/agkozak/zsh-z) that tracks your most visited directories and allows you to access them with very few keystrokes. ### Example + Assume that you have previously visited directory `~/.oh-my-zsh/plugins`. From any folder in your command line, you can quickly access it by using a regex match to this folder: ```bash @@ -11,6 +12,7 @@ Assume that you have previously visited directory `~/.oh-my-zsh/plugins`. From a ``` ### Setup + To enable z, add `z` to your `plugins` array in your zshrc file: ```zsh @@ -19,5 +21,4 @@ plugins=(... z) ### Further reading -For advanced usage and details of z, see [README](./README) (in man page format, copied from [rupa/z](https://github.com/rupa/z)). - +For advanced usage and details of z, see [MANUAL](./MANUAL.md) (copied from [agkozak/zsh-z](https://github.com/agkozak/zsh-z)). diff --git a/plugins/z/_z b/plugins/z/_z new file mode 100644 index 000000000..a493f35ba --- /dev/null +++ b/plugins/z/_z @@ -0,0 +1,82 @@ +#compdef zshz ${ZSHZ_CMD:-${_Z_CMD:-z}} +# +# Zsh-z - jump around with Zsh - A native Zsh version of z without awk, sort, +# date, or sed +# +# https://github.com/agkozak/zsh-z +# +# Copyright (c) 2018-2023 Alexandros Kozak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# z (https://github.com/rupa/z) is copyright (c) 2009 rupa deadwyler and +# licensed under the WTFPL license, Version 2.a +# +# shellcheck shell=ksh + +############################################################ +# Zsh-z COMPLETIONS +############################################################ +emulate -L zsh +(( ZSHZ_DEBUG )) && + setopt LOCAL_OPTIONS WARN_CREATE_GLOBAL NO_WARN_NESTED_VAR 2> /dev/null + +# TODO: This routine currently reproduces z's feature of allowing spaces to be +# used as wildcards in completions, so that +# +# z us lo bi +# +# can expand to +# +# z /usr/local/bin +# +# but it also reproduces z's buggy display on the commandline, viz. +# +# z us lo /usr/local/bin +# +# Address. + +local completions expl completion +local -a completion_list + +completions=$(zshz --complete ${(@)words:1}) +[[ -z $completions ]] && return 1 + +for completion in ${(f)completions[@]}; do + if (( ZSHZ_TILDE )) && [[ $completion == ${HOME}* ]]; then + completion="~${(q)${completion#${HOME}}}" + else + completion="${(q)completion}" + fi + completion_list+=( $completion ) +done + +_description -V completion_list expl 'directories' + +if [[ $ZSHZ_COMPLETION == 'legacy' ]]; then + compadd "${expl[@]}" -QU -- "${completion_list[@]}" +else + compadd "${expl[@]}" -QU -V zsh-z -- "${completion_list[@]}" +fi + +compstate[insert]=menu + +return 0 + +# vim: ft=zsh:fdm=indent:ts=2:et:sts=2:sw=2: diff --git a/plugins/z/img/demo.gif b/plugins/z/img/demo.gif new file mode 100644 index 000000000..247f52f4d Binary files /dev/null and b/plugins/z/img/demo.gif differ diff --git a/plugins/z/img/mit_license.svg b/plugins/z/img/mit_license.svg new file mode 100644 index 000000000..1c02079d7 --- /dev/null +++ b/plugins/z/img/mit_license.svg @@ -0,0 +1 @@ +licenselicenseMITMIT \ No newline at end of file diff --git a/plugins/z/img/zsh_4.3.11_plus.svg b/plugins/z/img/zsh_4.3.11_plus.svg new file mode 100644 index 000000000..f46d947d0 --- /dev/null +++ b/plugins/z/img/zsh_4.3.11_plus.svg @@ -0,0 +1 @@ +zshzsh4.3.11+4.3.11+ \ No newline at end of file diff --git a/plugins/z/z.1 b/plugins/z/z.1 deleted file mode 100644 index 182f98176..000000000 --- a/plugins/z/z.1 +++ /dev/null @@ -1,173 +0,0 @@ -.TH "Z" "1" "January 2013" "z" "User Commands" -.SH -NAME -z \- jump around -.SH -SYNOPSIS -z [\-chlrtx] [regex1 regex2 ... regexn] -.SH -AVAILABILITY -bash, zsh -.SH -DESCRIPTION -Tracks your most used directories, based on 'frecency'. -.P -After a short learning phase, \fBz\fR will take you to the most 'frecent' -directory that matches ALL of the regexes given on the command line, in order. - -For example, \fBz foo bar\fR would match \fB/foo/bar\fR but not \fB/bar/foo\fR. -.SH -OPTIONS -.TP -\fB\-c\fR -restrict matches to subdirectories of the current directory -.TP -\fB\-e\fR -echo the best match, don't cd -.TP -\fB\-h\fR -show a brief help message -.TP -\fB\-l\fR -list only -.TP -\fB\-r\fR -match by rank only -.TP -\fB\-t\fR -match by recent access only -.TP -\fB\-x\fR -remove the current directory from the datafile -.SH EXAMPLES -.TP 14 -\fBz foo\fR -cd to most frecent dir matching foo -.TP 14 -\fBz foo bar\fR -cd to most frecent dir matching foo, then bar -.TP 14 -\fBz -r foo\fR -cd to highest ranked dir matching foo -.TP 14 -\fBz -t foo\fR -cd to most recently accessed dir matching foo -.TP 14 -\fBz -l foo\fR -list all dirs matching foo (by frecency) -.SH -NOTES -.SS -Installation: -.P -Put something like this in your \fB$HOME/.bashrc\fR or \fB$HOME/.zshrc\fR: -.RS -.P -\fB. /path/to/z.sh\fR -.RE -.P -\fBcd\fR around for a while to build up the db. -.P -PROFIT!! -.P -Optionally: -.RS -Set \fB$_Z_CMD\fR to change the command name (default \fBz\fR). -.RE -.RS -Set \fB$_Z_DATA\fR to change the datafile (default \fB$HOME/.z\fR). -.RE -.RS -Set \fB$_Z_MAX_SCORE\fR lower to age entries out faster (default \fB9000\fR). -.RE -.RS -Set \fB$_Z_NO_RESOLVE_SYMLINKS\fR to prevent symlink resolution. -.RE -.RS -Set \fB$_Z_NO_PROMPT_COMMAND\fR to handle \fBPROMPT_COMMAND/precmd\fR yourself. -.RE -.RS -Set \fB$_Z_EXCLUDE_DIRS\fR to an array of directory trees to exclude. -.RE -.RS -Set \fB$_Z_OWNER\fR to allow usage when in 'sudo -s' mode. -.RE -.RS -(These settings should go in .bashrc/.zshrc before the line added above.) -.RE -.RS -Install the provided man page \fBz.1\fR somewhere in your \f$MANPATH, like -\fB/usr/local/man/man1\fR. -.RE -.SS -Aging: -The rank of directories maintained by \fBz\fR undergoes aging based on a simple -formula. The rank of each entry is incremented every time it is accessed. When -the sum of ranks is over 9000, all ranks are multiplied by 0.99. Entries with a -rank lower than 1 are forgotten. -.SS -Frecency: -Frecency is a portmanteau of 'recent' and 'frequency'. It is a weighted rank -that depends on how often and how recently something occurred. As far as I -know, Mozilla came up with the term. -.P -To \fBz\fR, a directory that has low ranking but has been accessed recently -will quickly have higher rank than a directory accessed frequently a long time -ago. -.P -Frecency is determined at runtime. -.SS -Common: -When multiple directories match all queries, and they all have a common prefix, -\fBz\fR will cd to the shortest matching directory, without regard to priority. -This has been in effect, if undocumented, for quite some time, but should -probably be configurable or reconsidered. -.SS -Tab Completion: -\fBz\fR supports tab completion. After any number of arguments, press TAB to -complete on directories that match each argument. Due to limitations of the -completion implementations, only the last argument will be completed in the -shell. -.P -Internally, \fBz\fR decides you've requested a completion if the last argument -passed is an absolute path to an existing directory. This may cause unexpected -behavior if the last argument to \fBz\fR begins with \fB/\fR. -.SH -ENVIRONMENT -A function \fB_z()\fR is defined. -.P -The contents of the variable \fB$_Z_CMD\fR is aliased to \fB_z 2>&1\fR. If not -set, \fB$_Z_CMD\fR defaults to \fBz\fR. -.P -The environment variable \fB$_Z_DATA\fR can be used to control the datafile -location. If it is not defined, the location defaults to \fB$HOME/.z\fR. -.P -The environment variable \fB$_Z_NO_RESOLVE_SYMLINKS\fR can be set to prevent -resolving of symlinks. If it is not set, symbolic links will be resolved when -added to the datafile. -.P -In bash, \fBz\fR appends a command to the \fBPROMPT_COMMAND\fR environment -variable to maintain its database. In zsh, \fBz\fR appends a function -\fB_z_precmd\fR to the \fBprecmd_functions\fR array. -.P -The environment variable \fB$_Z_NO_PROMPT_COMMAND\fR can be set if you want to -handle \fBPROMPT_COMMAND\fR or \fBprecmd\fR yourself. -.P -The environment variable \fB$_Z_EXCLUDE_DIRS\fR can be set to an array of -directory trees to exclude from tracking. \fB$HOME\fR is always excluded. -Directories must be full paths without trailing slashes. -.P -The environment variable \fB$_Z_OWNER\fR can be set to your username, to -allow usage of \fBz\fR when your sudo environment keeps \fB$HOME\fR set. -.SH -FILES -Data is stored in \fB$HOME/.z\fR. This can be overridden by setting the -\fB$_Z_DATA\fR environment variable. When initialized, \fBz\fR will raise an -error if this path is a directory, and not function correctly. -.P -A man page (\fBz.1\fR) is provided. -.SH -SEE ALSO -regex(7), pushd, popd, autojump, cdargs -.P -Please file bugs at https://github.com/rupa/z/ diff --git a/plugins/z/z.plugin.zsh b/plugins/z/z.plugin.zsh index 7d3eacac0..a41a4ae25 100644 --- a/plugins/z/z.plugin.zsh +++ b/plugins/z/z.plugin.zsh @@ -1,6 +1,1014 @@ -# Handle $0 according to the standard: +################################################################################ +# Zsh-z - jump around with Zsh - A native Zsh version of z without awk, sort, +# date, or sed +# +# https://github.com/agkozak/zsh-z +# +# Copyright (c) 2018-2023 Alexandros Kozak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# z (https://github.com/rupa/z) is copyright (c) 2009 rupa deadwyler and +# licensed under the WTFPL license, Version 2. +# +# Zsh-z maintains a jump-list of the directories you actually use. +# +# INSTALL: +# * put something like this in your .zshrc: +# source /path/to/zsh-z.plugin.zsh +# * cd around for a while to build up the database +# +# USAGE: +# * z foo cd to the most frecent directory matching foo +# * z foo bar cd to the most frecent directory matching both foo and bar +# (e.g. /foo/bat/bar/quux) +# * z -r foo cd to the highest ranked directory matching foo +# * z -t foo cd to most recently accessed directory matching foo +# * z -l foo List matches instead of changing directories +# * z -e foo Echo the best match without changing directories +# * z -c foo Restrict matches to subdirectories of PWD +# * z -x Remove a directory (default: PWD) from the database +# * z -xR Remove a directory (default: PWD) and its subdirectories from +# the database +# +# ENVIRONMENT VARIABLES: +# +# ZSHZ_CASE -> if `ignore', pattern matching is case-insensitive; if `smart', +# pattern matching is case-insensitive only when the pattern is all +# lowercase +# ZSHZ_CD -> the directory-changing command that is used (default: builtin cd) +# ZSHZ_CMD -> name of command (default: z) +# ZSHZ_COMPLETION -> completion method (default: 'frecent'; 'legacy' for +# alphabetic sorting) +# ZSHZ_DATA -> name of datafile (default: ~/.z) +# ZSHZ_EXCLUDE_DIRS -> array of directories to exclude from your database +# (default: empty) +# ZSHZ_KEEP_DIRS -> array of directories that should not be removed from the +# database, even if they are not currently available (default: empty) +# ZSHZ_MAX_SCORE -> maximum combined score the database entries can have +# before beginning to age (default: 9000) +# ZSHZ_NO_RESOLVE_SYMLINKS -> '1' prevents symlink resolution +# ZSHZ_OWNER -> your username (if you want use Zsh-z while using sudo -s) +# ZSHZ_UNCOMMON -> if 1, do not jump to "common directories," but rather drop +# subdirectories based on what the search string was (default: 0) +################################################################################ + +autoload -U is-at-least + +if ! is-at-least 4.3.11; then + print "Zsh-z requires Zsh v4.3.11 or higher." >&2 && exit +fi + +############################################################ +# The help message +# +# Globals: +# ZSHZ_CMD +############################################################ +_zshz_usage() { + print "Usage: ${ZSHZ_CMD:-${_Z_CMD:-z}} [OPTION]... [ARGUMENT] +Jump to a directory that you have visited frequently or recently, or a bit of both, based on the partial string ARGUMENT. + +With no ARGUMENT, list the directory history in ascending rank. + + --add Add a directory to the database + -c Only match subdirectories of the current directory + -e Echo the best match without going to it + -h Display this help and exit + -l List all matches without going to them + -r Match by rank + -t Match by recent access + -x Remove a directory from the database (by default, the current directory) + -xR Remove a directory and its subdirectories from the database (by default, the current directory)" | + fold -s -w $COLUMNS >&2 +} + +# Load zsh/datetime module, if necessary +(( ${+EPOCHSECONDS} )) || zmodload zsh/datetime + +# Global associative array for internal use +typeset -gA ZSHZ + +# Fallback utilities in case Zsh lacks zsh/files (as is the case with MobaXterm) +ZSHZ[CHOWN]='chown' +ZSHZ[MV]='mv' +ZSHZ[RM]='rm' +# Try to load zsh/files utilities +if [[ ${builtins[zf_chown]-} != 'defined' || + ${builtins[zf_mv]-} != 'defined' || + ${builtins[zf_rm]-} != 'defined' ]]; then + zmodload -F zsh/files b:zf_chown b:zf_mv b:zf_rm &> /dev/null +fi +# Use zsh/files, if it is available +[[ ${builtins[zf_chown]-} == 'defined' ]] && ZSHZ[CHOWN]='zf_chown' +[[ ${builtins[zf_mv]-} == 'defined' ]] && ZSHZ[MV]='zf_mv' +[[ ${builtins[zf_rm]-} == 'defined' ]] && ZSHZ[RM]='zf_rm' + + +# Load zsh/system, if necessary +[[ ${modules[zsh/system]-} == 'loaded' ]] || zmodload zsh/system &> /dev/null + +# Make sure ZSHZ_EXCLUDE_DIRS has been declared so that other scripts can +# simply append to it +(( ${+ZSHZ_EXCLUDE_DIRS} )) || typeset -gUa ZSHZ_EXCLUDE_DIRS + +# Determine if zsystem flock is available +zsystem supports flock &> /dev/null && ZSHZ[USE_FLOCK]=1 + +# Determine if `print -v' is supported +is-at-least 5.3.0 && ZSHZ[PRINTV]=1 + +############################################################ +# The Zsh-z Command +# +# Globals: +# ZSHZ +# ZSHZ_CASE +# ZSHZ_CD +# ZSHZ_COMPLETION +# ZSHZ_DATA +# ZSHZ_DEBUG +# ZSHZ_EXCLUDE_DIRS +# ZSHZ_KEEP_DIRS +# ZSHZ_MAX_SCORE +# ZSHZ_OWNER +# +# Arguments: +# $* Command options and arguments +############################################################ +zshz() { + + # Don't use `emulate -L zsh' - it breaks PUSHD_IGNORE_DUPS + setopt LOCAL_OPTIONS NO_KSH_ARRAYS NO_SH_WORD_SPLIT EXTENDED_GLOB UNSET + (( ZSHZ_DEBUG )) && setopt LOCAL_OPTIONS WARN_CREATE_GLOBAL + + local REPLY + local -a lines + + # Allow the user to specify a custom datafile in $ZSHZ_DATA (or legacy $_Z_DATA) + local custom_datafile="${ZSHZ_DATA:-$_Z_DATA}" + + # If a datafile was provided as a standalone file without a directory path + # print a warning and exit + if [[ -n ${custom_datafile} && ${custom_datafile} != */* ]]; then + print "ERROR: You configured a custom Zsh-z datafile (${custom_datafile}), but have not specified its directory." >&2 + exit + fi + + # If the user specified a datafile, use that or default to ~/.z + # If the datafile is a symlink, it gets dereferenced + local datafile=${${custom_datafile:-$HOME/.z}:A} + + # If the datafile is a directory, print a warning and exit + if [[ -d $datafile ]]; then + print "ERROR: Zsh-z's datafile (${datafile}) is a directory." >&2 + exit + fi + + # Make sure that the datafile exists before attempting to read it or lock it + # for writing + [[ -f $datafile ]] || { mkdir -p "${datafile:h}" && touch "$datafile" } + + # Bail if we don't own the datafile and $ZSHZ_OWNER is not set + [[ -z ${ZSHZ_OWNER:-${_Z_OWNER}} && -f $datafile && ! -O $datafile ]] && + return + + # Load the datafile into an array and parse it + lines=( ${(f)"$(< $datafile)"} ) + # Discard entries that are incomplete or incorrectly formatted + lines=( ${(M)lines:#/*\|[[:digit:]]##[.,]#[[:digit:]]#\|[[:digit:]]##} ) + + ############################################################ + # Add a path to or remove one from the datafile + # + # Globals: + # ZSHZ + # ZSHZ_EXCLUDE_DIRS + # ZSHZ_OWNER + # + # Arguments: + # $1 Which action to perform (--add/--remove) + # $2 The path to add + ############################################################ + _zshz_add_or_remove_path() { + local action=${1} + shift + + if [[ $action == '--add' ]]; then + + # TODO: The following tasks are now handled by _agkozak_precmd. Dead code? + + # Don't add $HOME + [[ $* == $HOME ]] && return + + # Don't track directory trees excluded in ZSHZ_EXCLUDE_DIRS + local exclude + for exclude in ${(@)ZSHZ_EXCLUDE_DIRS:-${(@)_Z_EXCLUDE_DIRS}}; do + case $* in + ${exclude}|${exclude}/*) return ;; + esac + done + fi + + # A temporary file that gets copied over the datafile if all goes well + local tempfile="${datafile}.${RANDOM}" + + # See https://github.com/rupa/z/pull/199/commits/ed6eeed9b70d27c1582e3dd050e72ebfe246341c + if (( ZSHZ[USE_FLOCK] )); then + + local lockfd + + # Grab exclusive lock (released when function exits) + zsystem flock -f lockfd "$datafile" 2> /dev/null || return + + fi + + integer tmpfd + case $action in + --add) + exec {tmpfd}>|"$tempfile" # Open up tempfile for writing + _zshz_update_datafile $tmpfd "$*" + local ret=$? + ;; + --remove) + local xdir # Directory to be removed + + if (( ${ZSHZ_NO_RESOLVE_SYMLINKS:-${_Z_NO_RESOLVE_SYMLINKS}} )); then + [[ -d ${${*:-${PWD}}:a} ]] && xdir=${${*:-${PWD}}:a} + else + [[ -d ${${*:-${PWD}}:A} ]] && xdir=${${*:-${PWD}}:a} + fi + + local -a lines_to_keep + if (( ${+opts[-R]} )); then + # Prompt user before deleting entire database + if [[ $xdir == '/' ]] && ! read -q "?Delete entire Zsh-z database? "; then + print && return 1 + fi + # All of the lines that don't match the directory to be deleted + lines_to_keep=( ${lines:#${xdir}\|*} ) + # Or its subdirectories + lines_to_keep=( ${lines_to_keep:#${xdir%/}/**} ) + else + # All of the lines that don't match the directory to be deleted + lines_to_keep=( ${lines:#${xdir}\|*} ) + fi + if [[ $lines != "$lines_to_keep" ]]; then + lines=( $lines_to_keep ) + else + return 1 # The $PWD isn't in the datafile + fi + exec {tmpfd}>|"$tempfile" # Open up tempfile for writing + print -u $tmpfd -l -- $lines + local ret=$? + ;; + esac + + if (( tmpfd != 0 )); then + # Close tempfile + exec {tmpfd}>&- + fi + + if (( ret != 0 )); then + # Avoid clobbering the datafile if the write to tempfile failed + ${ZSHZ[RM]} -f "$tempfile" + return $ret + fi + + local owner + owner=${ZSHZ_OWNER:-${_Z_OWNER}} + + if (( ZSHZ[USE_FLOCK] )); then + ${ZSHZ[MV]} "$tempfile" "$datafile" 2> /dev/null || ${ZSHZ[RM]} -f "$tempfile" + + if [[ -n $owner ]]; then + ${ZSHZ[CHOWN]} ${owner}:"$(id -ng ${owner})" "$datafile" + fi + else + if [[ -n $owner ]]; then + ${ZSHZ[CHOWN]} "${owner}":"$(id -ng "${owner}")" "$tempfile" + fi + ${ZSHZ[MV]} -f "$tempfile" "$datafile" 2> /dev/null || + ${ZSHZ[RM]} -f "$tempfile" + fi + + # In order to make z -x work, we have to disable zsh-z's adding + # to the database until the user changes directory and the + # chpwd_functions are run + if [[ $action == '--remove' ]]; then + ZSHZ[DIRECTORY_REMOVED]=1 + fi + } + + ############################################################ + # Read the current datafile contents, update them, "age" them + # when the total rank gets high enough, and print the new + # contents to STDOUT. + # + # Globals: + # ZSHZ_KEEP_DIRS + # ZSHZ_MAX_SCORE + # + # Arguments: + # $1 File descriptor linked to tempfile + # $2 Path to be added to datafile + ############################################################ + _zshz_update_datafile() { + + integer fd=$1 + local -A rank time + + # Characters special to the shell (such as '[]') are quoted with backslashes + # See https://github.com/rupa/z/issues/246 + local add_path=${(q)2} + + local -a existing_paths + local now=$EPOCHSECONDS line dir + local path_field rank_field time_field count x + + rank[$add_path]=1 + time[$add_path]=$now + + # Remove paths from database if they no longer exist + for line in $lines; do + if [[ ! -d ${line%%\|*} ]]; then + for dir in ${(@)ZSHZ_KEEP_DIRS}; do + if [[ ${line%%\|*} == ${dir}/* || + ${line%%\|*} == $dir || + $dir == '/' ]]; then + existing_paths+=( $line ) + fi + done + else + existing_paths+=( $line ) + fi + done + lines=( $existing_paths ) + + for line in $lines; do + path_field=${(q)line%%\|*} + rank_field=${${line%\|*}#*\|} + time_field=${line##*\|} + + # When a rank drops below 1, drop the path from the database + (( rank_field < 1 )) && continue + + if [[ $path_field == $add_path ]]; then + rank[$path_field]=$rank_field + (( rank[$path_field]++ )) + time[$path_field]=$now + else + rank[$path_field]=$rank_field + time[$path_field]=$time_field + fi + (( count += rank_field )) + done + if (( count > ${ZSHZ_MAX_SCORE:-${_Z_MAX_SCORE:-9000}} )); then + # Aging + for x in ${(k)rank}; do + print -u $fd -- "$x|$(( 0.99 * rank[$x] ))|${time[$x]}" || return 1 + done + else + for x in ${(k)rank}; do + print -u $fd -- "$x|${rank[$x]}|${time[$x]}" || return 1 + done + fi + } + + ############################################################ + # The original tab completion method + # + # String processing is smartcase -- case-insensitive if the + # search string is lowercase, case-sensitive if there are + # any uppercase letters. Spaces in the search string are + # treated as *'s in globbing. Read the contents of the + # datafile and print matches to STDOUT. + # + # Arguments: + # $1 The string to be completed + ############################################################ + _zshz_legacy_complete() { + + local line path_field path_field_normalized + + # Replace spaces in the search string with asterisks for globbing + 1=${1//[[:space:]]/*} + + for line in $lines; do + + path_field=${line%%\|*} + + path_field_normalized=$path_field + if (( ZSHZ_TRAILING_SLASH )); then + path_field_normalized=${path_field%/}/ + fi + + # If the search string is all lowercase, the search will be case-insensitive + if [[ $1 == "${1:l}" && ${path_field_normalized:l} == *${~1}* ]]; then + print -- $path_field + # Otherwise, case-sensitive + elif [[ $path_field_normalized == *${~1}* ]]; then + print -- $path_field + fi + + done + # TODO: Search strings with spaces in them are currently treated case- + # insensitively. + } + + ############################################################ + # `print' or `printf' to REPLY + # + # Variable assignment through command substitution, of the + # form + # + # foo=$( bar ) + # + # requires forking a subshell; on Cygwin/MSYS2/WSL1 that can + # be surprisingly slow. Zsh-z avoids doing that by printing + # values to the variable REPLY. Since Zsh v5.3.0 that has + # been possible with `print -v'; for earlier versions of the + # shell, the values are placed on the editing buffer stack + # and then `read' into REPLY. + # + # Globals: + # ZSHZ + # + # Arguments: + # Options and parameters for `print' + ############################################################ + _zshz_printv() { + # NOTE: For a long time, ZSH's `print -v' had a tendency + # to mangle multibyte strings: + # + # https://www.zsh.org/mla/workers/2020/msg00307.html + # + # The bug was fixed in late 2020: + # + # https://github.com/zsh-users/zsh/commit/b6ba74cd4eaec2b6cb515748cf1b74a19133d4a4#diff-32bbef18e126b837c87b06f11bfc61fafdaa0ed99fcb009ec53f4767e246b129 + # + # In order to support shells with the bug, we must use a form of `printf`, + # which does not exhibit the undesired behavior. See + # + # https://www.zsh.org/mla/workers/2020/msg00308.html + + if (( ZSHZ[PRINTV] )); then + builtin print -v REPLY -f %s $@ + else + builtin print -z $@ + builtin read -rz REPLY + fi + } + + ############################################################ + # If matches share a common root, find it, and put it in + # REPLY for _zshz_output to use. + # + # Arguments: + # $1 Name of associative array of matches and ranks + ############################################################ + _zshz_find_common_root() { + local -a common_matches + local x short + + common_matches=( ${(@Pk)1} ) + + for x in ${(@)common_matches}; do + if [[ -z $short ]] || (( $#x < $#short )) || [[ $x != ${short}/* ]]; then + short=$x + fi + done + + [[ $short == '/' ]] && return + + for x in ${(@)common_matches}; do + [[ $x != $short* ]] && return + done + + _zshz_printv -- $short + } + + ############################################################ + # Calculate a common root, if there is one. Then do one of + # the following: + # + # 1) Print a list of completions in frecent order; + # 2) List them (z -l) to STDOUT; or + # 3) Put a common root or best match into REPLY + # + # Globals: + # ZSHZ_UNCOMMON + # + # Arguments: + # $1 Name of an associative array of matches and ranks + # $2 The best match or best case-insensitive match + # $3 Whether to produce a completion, a list, or a root or + # match + ############################################################ + _zshz_output() { + + local match_array=$1 match=$2 format=$3 + local common k x + local -a descending_list output + local -A output_matches + + output_matches=( ${(Pkv)match_array} ) + + _zshz_find_common_root $match_array + common=$REPLY + + case $format in + + completion) + for k in ${(@k)output_matches}; do + _zshz_printv -f "%.2f|%s" ${output_matches[$k]} $k + descending_list+=( ${(f)REPLY} ) + REPLY='' + done + descending_list=( ${${(@On)descending_list}#*\|} ) + print -l $descending_list + ;; + + list) + local path_to_display + for x in ${(k)output_matches}; do + if (( ${output_matches[$x]} )); then + path_to_display=$x + (( ZSHZ_TILDE )) && + path_to_display=${path_to_display/#${HOME}/\~} + _zshz_printv -f "%-10d %s\n" ${output_matches[$x]} $path_to_display + output+=( ${(f)REPLY} ) + REPLY='' + fi + done + if [[ -n $common ]]; then + (( ZSHZ_TILDE )) && common=${common/#${HOME}/\~} + (( $#output > 1 )) && printf "%-10s %s\n" 'common:' $common + fi + # -lt + if (( $+opts[-t] )); then + for x in ${(@On)output}; do + print -- $x + done + # -lr + elif (( $+opts[-r] )); then + for x in ${(@on)output}; do + print -- $x + done + # -l + else + for x in ${(@on)output}; do + print $x + done + fi + ;; + + *) + if (( ! ZSHZ_UNCOMMON )) && [[ -n $common ]]; then + _zshz_printv -- $common + else + _zshz_printv -- ${(P)match} + fi + ;; + esac + } + + ############################################################ + # Match a pattern by rank, time, or a combination of the + # two, and output the results as completions, a list, or a + # best match. + # + # Globals: + # ZSHZ + # ZSHZ_CASE + # ZSHZ_KEEP_DIRS + # ZSHZ_OWNER + # + # Arguments: + # #1 Pattern to match + # $2 Matching method (rank, time, or [default] frecency) + # $3 Output format (completion, list, or [default] store + # in REPLY + ############################################################ + _zshz_find_matches() { + setopt LOCAL_OPTIONS NO_EXTENDED_GLOB + + local fnd=$1 method=$2 format=$3 + + local -a existing_paths + local line dir path_field rank_field time_field rank dx escaped_path_field + local -A matches imatches + local best_match ibest_match hi_rank=-9999999999 ihi_rank=-9999999999 + + # Remove paths from database if they no longer exist + for line in $lines; do + if [[ ! -d ${line%%\|*} ]]; then + for dir in ${(@)ZSHZ_KEEP_DIRS}; do + if [[ ${line%%\|*} == ${dir}/* || + ${line%%\|*} == $dir || + $dir == '/' ]]; then + existing_paths+=( $line ) + fi + done + else + existing_paths+=( $line ) + fi + done + lines=( $existing_paths ) + + for line in $lines; do + path_field=${line%%\|*} + rank_field=${${line%\|*}#*\|} + time_field=${line##*\|} + + case $method in + rank) rank=$rank_field ;; + time) (( rank = time_field - EPOCHSECONDS )) ;; + *) + # Frecency routine + (( dx = EPOCHSECONDS - time_field )) + rank=$(( 10000 * rank_field * (3.75/( (0.0001 * dx + 1) + 0.25)) )) + ;; + esac + + # Use spaces as wildcards + local q=${fnd//[[:space:]]/\*} + + # If $ZSHZ_TRAILING_SLASH is set, use path_field with a trailing slash for matching. + local path_field_normalized=$path_field + if (( ZSHZ_TRAILING_SLASH )); then + path_field_normalized=${path_field%/}/ + fi + + # If $ZSHZ_CASE is 'ignore', be case-insensitive. + # + # If it's 'smart', be case-insensitive unless the string to be matched + # includes capital letters. + # + # Otherwise, the default behavior of Zsh-z is to match case-sensitively if + # possible, then to fall back on a case-insensitive match if possible. + if [[ $ZSHZ_CASE == 'smart' && ${1:l} == $1 && + ${path_field_normalized:l} == ${~q:l} ]]; then + imatches[$path_field]=$rank + elif [[ $ZSHZ_CASE != 'ignore' && $path_field_normalized == ${~q} ]]; then + matches[$path_field]=$rank + elif [[ $ZSHZ_CASE != 'smart' && ${path_field_normalized:l} == ${~q:l} ]]; then + imatches[$path_field]=$rank + fi + + # Escape characters that would cause "invalid subscript" errors + # when accessing the associative array. + escaped_path_field=${path_field//'\'/'\\'} + escaped_path_field=${escaped_path_field//'`'/'\`'} + escaped_path_field=${escaped_path_field//'('/'\('} + escaped_path_field=${escaped_path_field//')'/'\)'} + escaped_path_field=${escaped_path_field//'['/'\['} + escaped_path_field=${escaped_path_field//']'/'\]'} + + if (( matches[$escaped_path_field] )) && + (( matches[$escaped_path_field] > hi_rank )); then + best_match=$path_field + hi_rank=${matches[$escaped_path_field]} + elif (( imatches[$escaped_path_field] )) && + (( imatches[$escaped_path_field] > ihi_rank )); then + ibest_match=$path_field + ihi_rank=${imatches[$escaped_path_field]} + ZSHZ[CASE_INSENSITIVE]=1 + fi + done + + # Return 1 when there are no matches + [[ -z $best_match && -z $ibest_match ]] && return 1 + + if [[ -n $best_match ]]; then + _zshz_output matches best_match $format + elif [[ -n $ibest_match ]]; then + _zshz_output imatches ibest_match $format + fi + } + + # THE MAIN ROUTINE + + local -A opts + + zparseopts -E -D -A opts -- \ + -add \ + -complete \ + c \ + e \ + h \ + -help \ + l \ + r \ + R \ + t \ + x + + if [[ $1 == '--' ]]; then + shift + elif [[ -n ${(M)@:#-*} && -z $compstate ]]; then + print "Improper option(s) given." + _zshz_usage + return 1 + fi + + local opt output_format method='frecency' fnd prefix req + + for opt in ${(k)opts}; do + case $opt in + --add) + [[ ! -d $* ]] && return 1 + local dir + # Cygwin and MSYS2 have a hard time with relative paths expressed from / + if [[ $OSTYPE == (cygwin|msys) && $PWD == '/' && $* != /* ]]; then + set -- "/$*" + fi + if (( ${ZSHZ_NO_RESOLVE_SYMLINKS:-${_Z_NO_RESOLVE_SYMLINKS}} )); then + dir=${*:a} + else + dir=${*:A} + fi + _zshz_add_or_remove_path --add "$dir" + return + ;; + --complete) + if [[ -s $datafile && ${ZSHZ_COMPLETION:-frecent} == 'legacy' ]]; then + _zshz_legacy_complete "$1" + return + fi + output_format='completion' + ;; + -c) [[ $* == ${PWD}/* || $PWD == '/' ]] || prefix="$PWD " ;; + -h|--help) + _zshz_usage + return + ;; + -l) output_format='list' ;; + -r) method='rank' ;; + -t) method='time' ;; + -x) + # Cygwin and MSYS2 have a hard time with relative paths expressed from / + if [[ $OSTYPE == (cygwin|msys) && $PWD == '/' && $* != /* ]]; then + set -- "/$*" + fi + _zshz_add_or_remove_path --remove $* + return + ;; + esac + done + req="$*" + fnd="$prefix$*" + + [[ -n $fnd && $fnd != "$PWD " ]] || { + [[ $output_format != 'completion' ]] && output_format='list' + } + + ######################################################### + # Allow the user to specify directory-changing command + # using $ZSHZ_CD (default: builtin cd). + # + # Globals: + # ZSHZ_CD + # + # Arguments: + # $* Path + ######################################################### + zshz_cd() { + setopt LOCAL_OPTIONS NO_WARN_CREATE_GLOBAL + + if [[ -z $ZSHZ_CD ]]; then + builtin cd "$*" + else + ${=ZSHZ_CD} "$*" + fi + } + + ######################################################### + # If $ZSHZ_ECHO == 1, display paths as you jump to them. + # If it is also the case that $ZSHZ_TILDE == 1, display + # the home directory as a tilde. + ######################################################### + _zshz_echo() { + if (( ZSHZ_ECHO )); then + if (( ZSHZ_TILDE )); then + print ${PWD/#${HOME}/\~} + else + print $PWD + fi + fi + } + + if [[ ${@: -1} == /* ]] && (( ! $+opts[-e] && ! $+opts[-l] )); then + # cd if possible; echo the new path if $ZSHZ_ECHO == 1 + [[ -d ${@: -1} ]] && zshz_cd ${@: -1} && _zshz_echo && return + fi + + # With option -c, make sure query string matches beginning of matches; + # otherwise look for matches anywhere in paths + + # zpm-zsh/colors has a global $c, so we'll avoid math expressions here + if [[ ! -z ${(tP)opts[-c]} ]]; then + _zshz_find_matches "$fnd*" $method $output_format + else + _zshz_find_matches "*$fnd*" $method $output_format + fi + + local ret2=$? + + local cd + cd=$REPLY + + # New experimental "uncommon" behavior + # + # If the best choice at this point is something like /foo/bar/foo/bar, and the # search pattern is `bar', go to /foo/bar/foo/bar; but if the search pattern + # is `foo', go to /foo/bar/foo + if (( ZSHZ_UNCOMMON )) && [[ -n $cd ]]; then + if [[ -n $cd ]]; then + + # In the search pattern, replace spaces with * + local q=${fnd//[[:space:]]/\*} + q=${q%/} # Trailing slash has to be removed + + # As long as the best match is not case-insensitive + if (( ! ZSHZ[CASE_INSENSITIVE] )); then + # Count the number of characters in $cd that $q matches + local q_chars=$(( ${#cd} - ${#${cd//${~q}/}} )) + # Try dropping directory elements from the right; stop when it affects + # how many times the search pattern appears + until (( ( ${#cd:h} - ${#${${cd:h}//${~q}/}} ) != q_chars )); do + cd=${cd:h} + done + + # If the best match is case-insensitive + else + local q_chars=$(( ${#cd} - ${#${${cd:l}//${~${q:l}}/}} )) + until (( ( ${#cd:h} - ${#${${${cd:h}:l}//${~${q:l}}/}} ) != q_chars )); do + cd=${cd:h} + done + fi + + ZSHZ[CASE_INSENSITIVE]=0 + fi + fi + + if (( ret2 == 0 )) && [[ -n $cd ]]; then + if (( $+opts[-e] )); then # echo + (( ZSHZ_TILDE )) && cd=${cd/#${HOME}/\~} + print -- "$cd" + else + # cd if possible; echo the new path if $ZSHZ_ECHO == 1 + [[ -d $cd ]] && zshz_cd "$cd" && _zshz_echo + fi + else + # if $req is a valid path, cd to it; echo the new path if $ZSHZ_ECHO == 1 + if ! (( $+opts[-e] || $+opts[-l] )) && [[ -d $req ]]; then + zshz_cd "$req" && _zshz_echo + else + return $ret2 + fi + fi +} + +alias ${ZSHZ_CMD:-${_Z_CMD:-z}}='zshz 2>&1' + +############################################################ +# precmd - add path to datafile unless `z -x' has just been +# run +# +# Globals: +# ZSHZ +############################################################ +_zshz_precmd() { + # Protect against `setopt NO_UNSET' + setopt LOCAL_OPTIONS UNSET + + # Do not add PWD to datafile when in HOME directory, or + # if `z -x' has just been run + [[ $PWD == "$HOME" ]] || (( ZSHZ[DIRECTORY_REMOVED] )) && return + + # Don't track directory trees excluded in ZSHZ_EXCLUDE_DIRS + local exclude + for exclude in ${(@)ZSHZ_EXCLUDE_DIRS:-${(@)_Z_EXCLUDE_DIRS}}; do + case $PWD in + ${exclude}|${exclude}/*) return ;; + esac + done + + # It appears that forking a subshell is so slow in Windows that it is better + # just to add the PWD to the datafile in the foreground + if [[ $OSTYPE == (cygwin|msys) ]]; then + zshz --add "$PWD" + else + (zshz --add "$PWD" &) + fi + + # See https://github.com/rupa/z/pull/247/commits/081406117ea42ccb8d159f7630cfc7658db054b6 + : $RANDOM +} + +############################################################ +# chpwd +# +# When the $PWD is removed from the datafile with `z -x', +# Zsh-z refrains from adding it again until the user has +# left the directory. +# +# Globals: +# ZSHZ +############################################################ +_zshz_chpwd() { + ZSHZ[DIRECTORY_REMOVED]=0 +} + +autoload -Uz add-zsh-hook + +add-zsh-hook precmd _zshz_precmd +add-zsh-hook chpwd _zshz_chpwd + +############################################################ +# Completion +############################################################ + +# Standardized $0 handling # https://zdharma-continuum.github.io/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" 0="${${(M)0:#/*}:-$PWD/$0}" -source "${0:h}/z.sh" +(( ${fpath[(ie)${0:A:h}]} <= ${#fpath} )) || fpath=( "${0:A:h}" "${fpath[@]}" ) + +############################################################ +# zsh-z functions +############################################################ +ZSHZ[FUNCTIONS]='_zshz_usage + _zshz_add_or_remove_path + _zshz_update_datafile + _zshz_legacy_complete + _zshz_printv + _zshz_find_common_root + _zshz_output + _zshz_find_matches + zshz + _zshz_precmd + _zshz_chpwd + _zshz' + +############################################################ +# Enable WARN_NESTED_VAR for functions listed in +# ZSHZ[FUNCTIONS] +############################################################ +(( ${+ZSHZ_DEBUG} )) && () { + if is-at-least 5.4.0; then + local x + for x in ${=ZSHZ[FUNCTIONS]}; do + functions -W $x + done + fi +} + +############################################################ +# Unload function +# +# See https://github.com/agkozak/Zsh-100-Commits-Club/blob/master/Zsh-Plugin-Standard.adoc#unload-fun +# +# Globals: +# ZSHZ +# ZSHZ_CMD +############################################################ +zsh-z_plugin_unload() { + emulate -L zsh + + add-zsh-hook -D precmd _zshz_precmd + add-zsh-hook -d chpwd _zshz_chpwd + + local x + for x in ${=ZSHZ[FUNCTIONS]}; do + (( ${+functions[$x]} )) && unfunction $x + done + + unset ZSHZ + + fpath=( "${(@)fpath:#${0:A:h}}" ) + + (( ${+aliases[${ZSHZ_CMD:-${_Z_CMD:-z}}]} )) && + unalias ${ZSHZ_CMD:-${_Z_CMD:-z}} + + unfunction $0 +} + +# vim: fdm=indent:ts=2:et:sts=2:sw=2: diff --git a/plugins/z/z.sh b/plugins/z/z.sh deleted file mode 100644 index 67f504e27..000000000 --- a/plugins/z/z.sh +++ /dev/null @@ -1,267 +0,0 @@ -# Copyright (c) 2009 rupa deadwyler. Licensed under the WTFPL license, Version 2 - -# maintains a jump-list of the directories you actually use -# -# INSTALL: -# * put something like this in your .bashrc/.zshrc: -# . /path/to/z.sh -# * cd around for a while to build up the db -# * PROFIT!! -# * optionally: -# set $_Z_CMD in .bashrc/.zshrc to change the command (default z). -# set $_Z_DATA in .bashrc/.zshrc to change the datafile (default ~/.z). -# set $_Z_MAX_SCORE lower to age entries out faster (default 9000). -# set $_Z_NO_RESOLVE_SYMLINKS to prevent symlink resolution. -# set $_Z_NO_PROMPT_COMMAND if you're handling PROMPT_COMMAND yourself. -# set $_Z_EXCLUDE_DIRS to an array of directories to exclude. -# set $_Z_OWNER to your username if you want use z while sudo with $HOME kept -# -# USE: -# * z foo # cd to most frecent dir matching foo -# * z foo bar # cd to most frecent dir matching foo and bar -# * z -r foo # cd to highest ranked dir matching foo -# * z -t foo # cd to most recently accessed dir matching foo -# * z -l foo # list matches instead of cd -# * z -e foo # echo the best match, don't cd -# * z -c foo # restrict matches to subdirs of $PWD -# * z -x # remove the current directory from the datafile -# * z -h # show a brief help message - -[ -d "${_Z_DATA:-$HOME/.z}" ] && { - echo "ERROR: z.sh's datafile (${_Z_DATA:-$HOME/.z}) is a directory." -} - -_z() { - - local datafile="${_Z_DATA:-$HOME/.z}" - - # if symlink, dereference - [ -h "$datafile" ] && datafile=$(readlink "$datafile") - - # bail if we don't own ~/.z and $_Z_OWNER not set - [ -z "$_Z_OWNER" -a -f "$datafile" -a ! -O "$datafile" ] && return - - _z_dirs () { - [ -f "$datafile" ] || return - - local line - while read line; do - # only count directories - [ -d "${line%%\|*}" ] && echo "$line" - done < "$datafile" - return 0 - } - - # add entries - if [ "$1" = "--add" ]; then - shift - - # $HOME and / aren't worth matching - [ "$*" = "$HOME" -o "$*" = '/' ] && return - - # don't track excluded directory trees - if [ ${#_Z_EXCLUDE_DIRS[@]} -gt 0 ]; then - local exclude - for exclude in "${_Z_EXCLUDE_DIRS[@]}"; do - case "$*" in "$exclude"*) return;; esac - done - fi - - # maintain the data file - local tempfile="$datafile.$RANDOM" - local score=${_Z_MAX_SCORE:-9000} - _z_dirs | awk -v path="$*" -v now="$(date +%s)" -v score=$score -F"|" ' - BEGIN { - rank[path] = 1 - time[path] = now - } - $2 >= 1 { - # drop ranks below 1 - if( $1 == path ) { - rank[$1] = $2 + 1 - time[$1] = now - } else { - rank[$1] = $2 - time[$1] = $3 - } - count += $2 - } - END { - if( count > score ) { - # aging - for( x in rank ) print x "|" 0.99*rank[x] "|" time[x] - } else for( x in rank ) print x "|" rank[x] "|" time[x] - } - ' 2>/dev/null >| "$tempfile" - # do our best to avoid clobbering the datafile in a race condition. - if [ $? -ne 0 -a -f "$datafile" ]; then - env rm -f "$tempfile" - else - [ "$_Z_OWNER" ] && chown $_Z_OWNER:"$(id -ng $_Z_OWNER)" "$tempfile" - env mv -f "$tempfile" "$datafile" || env rm -f "$tempfile" - fi - - # tab completion - elif [ "$1" = "--complete" -a -s "$datafile" ]; then - _z_dirs | awk -v q="$2" -F"|" ' - BEGIN { - q = substr(q, 3) - if( q == tolower(q) ) imatch = 1 - gsub(/ /, ".*", q) - } - { - if( imatch ) { - if( tolower($1) ~ q ) print $1 - } else if( $1 ~ q ) print $1 - } - ' 2>/dev/null - - else - # list/go - local echo fnd last list opt typ - while [ "$1" ]; do case "$1" in - --) while [ "$1" ]; do shift; fnd="$fnd${fnd:+ }$1";done;; - -*) opt=${1:1}; while [ "$opt" ]; do case ${opt:0:1} in - c) fnd="^$PWD $fnd";; - e) echo=1;; - h) echo "${_Z_CMD:-z} [-cehlrtx] args" >&2; return;; - l) list=1;; - r) typ="rank";; - t) typ="recent";; - x) sed -i -e "\:^${PWD}|.*:d" "$datafile";; - esac; opt=${opt:1}; done;; - *) fnd="$fnd${fnd:+ }$1";; - esac; last=$1; [ "$#" -gt 0 ] && shift; done - [ "$fnd" -a "$fnd" != "^$PWD " ] || list=1 - - # if we hit enter on a completion just go there - case "$last" in - # completions will always start with / - /*) [ -z "$list" -a -d "$last" ] && builtin cd "$last" && return;; - esac - - # no file yet - [ -f "$datafile" ] || return - - local cd - cd="$( < <( _z_dirs ) awk -v t="$(date +%s)" -v list="$list" -v typ="$typ" -v q="$fnd" -F"|" ' - function frecent(rank, time) { - # relate frequency and time - dx = t - time - return int(10000 * rank * (3.75/((0.0001 * dx + 1) + 0.25))) - } - function output(matches, best_match, common) { - # list or return the desired directory - if( list ) { - if( common ) { - printf "%-10s %s\n", "common:", common > "/dev/stderr" - } - cmd = "sort -n >&2" - for( x in matches ) { - if( matches[x] ) { - printf "%-10s %s\n", matches[x], x | cmd - } - } - } else { - if( common && !typ ) best_match = common - print best_match - } - } - function common(matches) { - # find the common root of a list of matches, if it exists - for( x in matches ) { - if( matches[x] && (!short || length(x) < length(short)) ) { - short = x - } - } - if( short == "/" ) return - for( x in matches ) if( matches[x] && index(x, short) != 1 ) { - return - } - return short - } - BEGIN { - gsub(" ", ".*", q) - hi_rank = ihi_rank = -9999999999 - } - { - if( typ == "rank" ) { - rank = $2 - } else if( typ == "recent" ) { - rank = $3 - t - } else rank = frecent($2, $3) - if( $1 ~ q ) { - matches[$1] = rank - } else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank - if( matches[$1] && matches[$1] > hi_rank ) { - best_match = $1 - hi_rank = matches[$1] - } else if( imatches[$1] && imatches[$1] > ihi_rank ) { - ibest_match = $1 - ihi_rank = imatches[$1] - } - } - END { - # prefer case sensitive - if( best_match ) { - output(matches, best_match, common(matches)) - exit - } else if( ibest_match ) { - output(imatches, ibest_match, common(imatches)) - exit - } - exit(1) - } - ')" - - if [ "$?" -eq 0 ]; then - if [ "$cd" ]; then - if [ "$echo" ]; then echo "$cd"; else builtin cd "$cd"; fi - fi - else - return $? - fi - fi -} - -alias ${_Z_CMD:-z}='_z 2>&1' - -[ "$_Z_NO_RESOLVE_SYMLINKS" ] || _Z_RESOLVE_SYMLINKS="-P" - -if type compctl >/dev/null 2>&1; then - # zsh - [ "$_Z_NO_PROMPT_COMMAND" ] || { - # populate directory list, avoid clobbering any other precmds. - if [ "$_Z_NO_RESOLVE_SYMLINKS" ]; then - _z_precmd() { - (_z --add "${PWD:a}" &) - : $RANDOM - } - else - _z_precmd() { - (_z --add "${PWD:A}" &) - : $RANDOM - } - fi - [[ -n "${precmd_functions[(r)_z_precmd]}" ]] || { - precmd_functions[$(($#precmd_functions+1))]=_z_precmd - } - } - _z_zsh_tab_completion() { - # tab completion - local compl - read -l compl - reply=(${(f)"$(_z --complete "$compl")"}) - } - compctl -U -K _z_zsh_tab_completion _z -elif type complete >/dev/null 2>&1; then - # bash - # tab completion - complete -o filenames -C '_z --complete "$COMP_LINE"' ${_Z_CMD:-z} - [ "$_Z_NO_PROMPT_COMMAND" ] || { - # populate directory list. avoid clobbering other PROMPT_COMMANDs. - grep "_z --add" <<< "$PROMPT_COMMAND" >/dev/null || { - PROMPT_COMMAND="$PROMPT_COMMAND"$'\n''(_z --add "$(command pwd '$_Z_RESOLVE_SYMLINKS' 2>/dev/null)" 2>/dev/null &);' - } - } -fi diff --git a/plugins/zsh-interactive-cd/LICENSE b/plugins/zsh-interactive-cd/LICENSE new file mode 100644 index 000000000..40b3f8d7a --- /dev/null +++ b/plugins/zsh-interactive-cd/LICENSE @@ -0,0 +1,375 @@ +Copyright 2017-2018 Henry Chang + +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/plugins/zsh-interactive-cd/README.md b/plugins/zsh-interactive-cd/README.md index c8337fbc8..4bffbf04a 100644 --- a/plugins/zsh-interactive-cd/README.md +++ b/plugins/zsh-interactive-cd/README.md @@ -1,23 +1,15 @@ # zsh-interactive-cd -This plugin adds a fish-like interactive tab completion for the `cd` command. +## Demo -To use it, add `zsh-interactive-cd` to the plugins array of your zshrc file: -```zsh -plugins=(... zsh-interactive-cd) -``` +![demo](demo.gif) -![demo](https://user-images.githubusercontent.com/1441704/74360670-cb202900-4dc5-11ea-9734-f60caf726e85.gif) +## Installation + +1. Install [fzf](https://github.com/junegunn/fzf) by following its [installation instruction](https://github.com/junegunn/fzf#installation). + +2. Source `zsh-interactive-cd.plugin.zsh` in `.zshrc`. ## Usage Press tab for completion as usual, it'll launch fzf automatically. Check fzf’s [readme](https://github.com/junegunn/fzf#search-syntax) for more search syntax usage. - -## Requirements - -This plugin requires [fzf](https://github.com/junegunn/fzf). Install it by following -its [installation instructions](https://github.com/junegunn/fzf#installation). - -## Author - -[Henry Chang](https://github.com/changyuheng) diff --git a/plugins/zsh-interactive-cd/demo.gif b/plugins/zsh-interactive-cd/demo.gif new file mode 100644 index 000000000..3568ecf95 Binary files /dev/null and b/plugins/zsh-interactive-cd/demo.gif differ diff --git a/plugins/zsh-interactive-cd/zsh-interactive-cd.plugin.zsh b/plugins/zsh-interactive-cd/zsh-interactive-cd.plugin.zsh index b0520c239..0ae9d50a7 100644 --- a/plugins/zsh-interactive-cd/zsh-interactive-cd.plugin.zsh +++ b/plugins/zsh-interactive-cd/zsh-interactive-cd.plugin.zsh @@ -1,4 +1,10 @@ -# Copyright (c) 2017 Henry Chang +#!/usr/bin/env zsh +# +# Copyright 2017-2018 Henry Chang +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. __zic_fzf_prog() { [ -n "$TMUX_PANE" ] && [ "${FZF_TMUX:-0}" != 0 ] && [ ${LINES:-40} -gt 15 ] \ @@ -17,7 +23,7 @@ __zic_matched_subdir_list() { length=0 fi find -L "$dir" -mindepth 1 -maxdepth 1 -type d 2>/dev/null \ - | cut -b $(( ${length} + 2 ))- | sed '/^$/d' | while read -r line; do + | cut -b $(( ${length} + 2 ))- | command sed '/^$/d' | while read -r line; do if [[ "${line[1]}" == "." ]]; then continue fi @@ -32,13 +38,19 @@ __zic_matched_subdir_list() { seg=$(basename -- "$1") starts_with_dir=$( \ find -L "$dir" -mindepth 1 -maxdepth 1 -type d \ - 2>/dev/null | cut -b $(( ${length} + 2 ))- | sed '/^$/d' \ + 2>/dev/null | cut -b $(( ${length} + 2 ))- | command sed '/^$/d' \ | while read -r line; do if [[ "${seg[1]}" != "." && "${line[1]}" == "." ]]; then continue fi - if [[ "$line" == "$seg"* ]]; then - echo "$line" + if [ "$zic_case_insensitive" = "true" ]; then + if [[ "$line:u" == "$seg:u"* ]]; then + echo "$line" + fi + else + if [[ "$line" == "$seg"* ]]; then + echo "$line" + fi fi done ) @@ -46,19 +58,36 @@ __zic_matched_subdir_list() { echo "$starts_with_dir" else find -L "$dir" -mindepth 1 -maxdepth 1 -type d \ - 2>/dev/null | cut -b $(( ${length} + 2 ))- | sed '/^$/d' \ + 2>/dev/null | cut -b $(( ${length} + 2 ))- | command sed '/^$/d' \ | while read -r line; do if [[ "${seg[1]}" != "." && "${line[1]}" == "." ]]; then continue fi - if [[ "$line" == *"$seg"* ]]; then - echo "$line" + if [ "$zic_case_insensitive" = "true" ]; then + if [[ "$line:u" == *"$seg:u"* ]]; then + echo "$line" + fi + else + if [[ "$line" == *"$seg"* ]]; then + echo "$line" + fi fi done fi fi } +__zic_fzf_bindings() { + autoload is-at-least + fzf=$(__zic_fzf_prog) + + if $(is-at-least '0.21.0' $(${=fzf} --version)); then + echo 'shift-tab:up,tab:down,bspace:backward-delete-char/eof' + else + echo 'shift-tab:up,tab:down' + fi +} + _zic_list_generator() { __zic_matched_subdir_list "${(Q)@[-1]}" | sort } @@ -75,6 +104,7 @@ _zic_complete() { fi fzf=$(__zic_fzf_prog) + fzf_bindings=$(__zic_fzf_bindings) if [ $(echo $l | wc -l) -eq 1 ]; then matches=${(q)l} @@ -82,7 +112,7 @@ _zic_complete() { matches=$(echo $l \ | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} \ --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS \ - --bind 'shift-tab:up,tab:down'" ${=fzf} \ + --bind '${fzf_bindings}'" ${=fzf} \ | while read -r item; do echo -n "${(q)item} " done) @@ -144,5 +174,7 @@ zic-completion() { } zle -N zic-completion -bindkey -M emacs '^I' zic-completion -bindkey -M viins '^I' zic-completion +if [ -z $zic_custom_binding ]; then + zic_custom_binding='^I' +fi +bindkey "${zic_custom_binding}" zic-completion diff --git a/plugins/zsh-navigation-tools/n-list b/plugins/zsh-navigation-tools/n-list index f25db8f60..a852b083a 100644 --- a/plugins/zsh-navigation-tools/n-list +++ b/plugins/zsh-navigation-tools/n-list @@ -467,7 +467,7 @@ while (( 1 )); do elif [ -n "$keypad" ]; then final_key="$keypad" else - _nlist_status_msg "Inproper input detected" + _nlist_status_msg "Improper input detected" zcurses refresh main inner fi diff --git a/themes/af-magic.zsh-theme b/themes/af-magic.zsh-theme index 2ef9b02d7..70549d01f 100644 --- a/themes/af-magic.zsh-theme +++ b/themes/af-magic.zsh-theme @@ -6,11 +6,12 @@ # dashed separator size function afmagic_dashes { # check either virtualenv or condaenv variables - local python_env="${VIRTUAL_ENV:-$CONDA_DEFAULT_ENV}" + local python_env_dir="${VIRTUAL_ENV:-$CONDA_DEFAULT_ENV}" + local python_env="${python_env_dir##*/}" # if there is a python virtual environment and it is displayed in # the prompt, account for it when returning the number of dashes - if [[ -n "$python_env" && "$PS1" = \(* ]]; then + if [[ -n "$python_env" && "$PS1" = *\(${python_env}\)* ]]; then echo $(( COLUMNS - ${#python_env} - 3 )) else echo $COLUMNS diff --git a/themes/agnoster.zsh-theme b/themes/agnoster.zsh-theme index 5f4efe813..aa274a5bb 100644 --- a/themes/agnoster.zsh-theme +++ b/themes/agnoster.zsh-theme @@ -109,13 +109,26 @@ prompt_git() { if [[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]]; then repo_path=$(git rev-parse --git-dir 2>/dev/null) dirty=$(parse_git_dirty) - ref=$(git symbolic-ref HEAD 2> /dev/null) || ref="➦ $(git rev-parse --short HEAD 2> /dev/null)" + ref=$(git symbolic-ref HEAD 2> /dev/null) || \ + ref="◈ $(git describe --exact-match --tags HEAD 2> /dev/null)" || \ + ref="➦ $(git rev-parse --short HEAD 2> /dev/null)" if [[ -n $dirty ]]; then prompt_segment yellow black else prompt_segment green $CURRENT_FG fi + local ahead behind + ahead=$(git log --oneline @{upstream}.. 2>/dev/null) + behind=$(git log --oneline ..@{upstream} 2>/dev/null) + if [[ -n "$ahead" ]] && [[ -n "$behind" ]]; then + PL_BRANCH_CHAR=$'\u21c5' + elif [[ -n "$ahead" ]]; then + PL_BRANCH_CHAR=$'\u21b1' + elif [[ -n "$behind" ]]; then + PL_BRANCH_CHAR=$'\u21b0' + fi + if [[ -e "${repo_path}/BISECT_LOG" ]]; then mode=" " elif [[ -e "${repo_path}/MERGE_HEAD" ]]; then diff --git a/themes/amuse.zsh-theme b/themes/amuse.zsh-theme index 3f7ec0bc5..d787fdaa4 100644 --- a/themes/amuse.zsh-theme +++ b/themes/amuse.zsh-theme @@ -11,8 +11,14 @@ ZSH_THEME_RUBY_PROMPT_PREFIX="%{$fg_bold[red]%}‹" ZSH_THEME_RUBY_PROMPT_SUFFIX="›%{$reset_color%}" PROMPT=' -%{$fg_bold[green]%}%~%{$reset_color%}$(git_prompt_info) ⌚ %{$fg_bold[red]%}%*%{$reset_color%} +%{$fg_bold[green]%}%~%{$reset_color%}$(git_prompt_info)$(virtualenv_prompt_info) ⌚ %{$fg_bold[red]%}%*%{$reset_color%} $ ' RPROMPT='$(ruby_prompt_info)' +VIRTUAL_ENV_DISABLE_PROMPT=0 +ZSH_THEME_VIRTUAL_ENV_PROMPT_PREFIX=" %{$fg[green]%}🐍" +ZSH_THEME_VIRTUAL_ENV_PROMPT_SUFFIX="%{$reset_color%}" +ZSH_THEME_VIRTUALENV_PREFIX=$ZSH_THEME_VIRTUAL_ENV_PROMPT_PREFIX +ZSH_THEME_VIRTUALENV_SUFFIX=$ZSH_THEME_VIRTUAL_ENV_PROMPT_SUFFIX + diff --git a/themes/avit.zsh-theme b/themes/avit.zsh-theme index f90ba331b..206274462 100644 --- a/themes/avit.zsh-theme +++ b/themes/avit.zsh-theme @@ -11,7 +11,12 @@ $(_user_host)${_current_dir} $(git_prompt_info) $(ruby_prompt_info) PROMPT2='%{%(!.${fg[red]}.${fg[white]})%}◀%{$reset_color%} ' -RPROMPT='$(vi_mode_prompt_info)%{$(echotc UP 1)%}$(_git_time_since_commit) $(git_prompt_status) ${_return_status}%{$(echotc DO 1)%}' +__RPROMPT='$(vi_mode_prompt_info)%{$(echotc UP 1)%}$(_git_time_since_commit) $(git_prompt_status) ${_return_status}%{$(echotc DO 1)%}' +if [[ -z $RPROMPT ]]; then + RPROMPT=$__RPROMPT +else + RPROMPT="${RPROMPT} ${__RPROMPT}" +fi function _user_host() { local me @@ -82,4 +87,4 @@ ZSH_THEME_GIT_TIME_SINCE_COMMIT_NEUTRAL="%{$fg[white]%}" # LS colors, made with https://geoff.greer.fm/lscolors/ export LSCOLORS="exfxcxdxbxegedabagacad" export LS_COLORS='di=34;40:ln=35;40:so=32;40:pi=33;40:ex=31;40:bd=34;46:cd=34;43:su=0;41:sg=0;46:tw=0;42:ow=0;43:' -export GREP_COLOR='1;33' +export GREP_COLORS='mt=1;33' diff --git a/themes/bureau.zsh-theme b/themes/bureau.zsh-theme index 698aa2ff8..e87a594cd 100644 --- a/themes/bureau.zsh-theme +++ b/themes/bureau.zsh-theme @@ -15,6 +15,7 @@ ZSH_THEME_GIT_PROMPT_BEHIND="%{$fg[magenta]%}▾%{$reset_color%}" ZSH_THEME_GIT_PROMPT_STAGED="%{$fg_bold[green]%}●%{$reset_color%}" ZSH_THEME_GIT_PROMPT_UNSTAGED="%{$fg_bold[yellow]%}●%{$reset_color%}" ZSH_THEME_GIT_PROMPT_UNTRACKED="%{$fg_bold[red]%}●%{$reset_color%}" +ZSH_THEME_GIT_PROMPT_STASHED="(%{$fg_bold[blue]%}✹%{$reset_color%})" bureau_git_info () { local ref @@ -67,6 +68,12 @@ bureau_git_status() { } bureau_git_prompt() { + # ignore non git folders and hidden repos (adapted from lib/git.zsh) + if ! command git rev-parse --git-dir &> /dev/null \ + || [[ "$(command git config --get oh-my-zsh.hide-info 2>/dev/null)" == 1 ]]; then + return + fi + # check git information local gitinfo=$(bureau_git_info) if [[ -z "$gitinfo" ]]; then diff --git a/themes/fino-time.zsh-theme b/themes/fino-time.zsh-theme index c7e2d965e..3f9360ac5 100644 --- a/themes/fino-time.zsh-theme +++ b/themes/fino-time.zsh-theme @@ -12,6 +12,7 @@ # Also borrowing from http://stevelosh.com/blog/2010/02/my-extravagant-zsh-prompt/ function virtualenv_info { + [ $CONDA_DEFAULT_ENV ] && echo "($CONDA_DEFAULT_ENV) " [ $VIRTUAL_ENV ] && echo '('`basename $VIRTUAL_ENV`') ' } diff --git a/themes/gallois.zsh-theme b/themes/gallois.zsh-theme index bb97bfb17..3fc349072 100644 --- a/themes/gallois.zsh-theme +++ b/themes/gallois.zsh-theme @@ -1,24 +1,140 @@ # Depends on the git plugin for work_in_progress() (( $+functions[work_in_progress] )) || work_in_progress() {} -ZSH_THEME_GIT_PROMPT_PREFIX="%{$reset_color%}%{$fg[green]%}[" -ZSH_THEME_GIT_PROMPT_SUFFIX="]%{$reset_color%}" -ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[red]%}*%{$reset_color%}" +ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg[cyan]%}[%{$fg[green]%}" +ZSH_THEME_GIT_PROMPT_SUFFIX="%{$fg[cyan]%}]" +ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[red]%}" ZSH_THEME_GIT_PROMPT_CLEAN="" # Customized git status, oh-my-zsh currently does not allow render dirty status before branch git_custom_status() { local branch=$(git_current_branch) [[ -n "$branch" ]] || return 0 - echo "$(parse_git_dirty)\ -%{${fg_bold[yellow]}%}$(work_in_progress)%{$reset_color%}\ -${ZSH_THEME_GIT_PROMPT_PREFIX}${branch}${ZSH_THEME_GIT_PROMPT_SUFFIX}" + print "%{${fg_bold[yellow]}%}$(work_in_progress)%{$reset_color%}\ +${ZSH_THEME_GIT_PROMPT_PREFIX}$(parse_git_dirty)${branch}\ +${ZSH_THEME_GIT_PROMPT_SUFFIX}" +} +autoload -U colors && colors + +#export VCS_PROMPT=hg_prompt_info +export VCS_PROMPT=git_custom_status + +base_prompt="%{$fg[cyan]%}[%~% ]%(?.%{$fg[green]%}.%{$fg[red]%})%B$%b " +custom_prompt="" +last_run_time="" +last_vcs_info="" + + +function pipestatus_parse { + PIPESTATUS="$pipestatus" + ERROR=0 + for i in "${(z)PIPESTATUS}"; do + if [[ "$i" -ne 0 ]]; then + ERROR=1 + fi + done + + if [[ "$ERROR" -ne 0 ]]; then + print "[%{$fg[red]%}$PIPESTATUS%{$fg[cyan]%}]" + fi } -# RVM component of prompt -ZSH_THEME_RUBY_PROMPT_PREFIX="%{$fg[red]%}[" -ZSH_THEME_RUBY_PROMPT_SUFFIX="]%{$reset_color%}" # Combine it all into a final right-side prompt -RPS1="\$(git_custom_status)\$(ruby_prompt_info)${RPS1:+ $RPS1}" PROMPT='%{$fg[cyan]%}[%~% ]%(?.%{$fg[green]%}.%{$fg[red]%})%B$%b ' +function preexec() { + last_run_time=$(perl -MTime::HiRes=time -e 'printf "%.9f\n", time') +} + +function duration() { + local duration + local now=$(perl -MTime::HiRes=time -e 'printf "%.9f\n", time') + local last=$1 + local last_split=("${(@s/./)last}") + local now_split=("${(@s/./)now}") + local T=$((now_split[1] - last_split[1])) + local D=$((T/60/60/24)) + local H=$((T/60/60%24)) + local M=$((T/60%60)) + local S=$((T%60)) + local s=$(((now_split[2] - last_split[2]) / 1000000000.)) + local m=$(((now_split[2] - last_split[2]) / 1000000.)) + + (( $D > 0 )) && duration+="${D}d" + (( $H > 0 )) && duration+="${H}h" + (( $M > 0 )) && duration+="${M}m" + + if [[ $S -le 0 ]]; then + printf "%ims" "$m" + else + if ! [[ -z $duration ]] && printf "%s" "$duration" + local sec_milli=$((S + s)) + printf "%.3fs" "$sec_milli" + fi +} + +function precmd() { + RETVAL=$(pipestatus_parse) + local info="" + + if [ ! -z "$last_run_time" ]; then + local elapsed=$(duration $last_run_time) + last_run_time=$(print $last_run_time | tr -d ".") + if [ $(( $(perl -MTime::HiRes=time -e 'printf "%.9f\n", time' | tr -d ".") - $last_run_time )) -gt $(( 120 * 1000 * 1000 * 1000 )) ]; then + local elapsed_color="%{$fg[magenta]%}" + elif [ $(( $(perl -MTime::HiRes=time -e 'printf "%.9f\n", time' | tr -d ".") - $last_run_time )) -gt $(( 60 * 1000 * 1000 * 1000 )) ]; then + local elapsed_color="%{$fg[red]%}" + elif [ $(( $(perl -MTime::HiRes=time -e 'printf "%.9f\n", time' | tr -d ".") - $last_run_time )) -gt $(( 10 * 1000 * 1000 * 1000 )) ]; then + local elapsed_color="%{$fg[yellow]%}" + else + local elapsed_color="%{$fg[green]%}" + fi + info=$(printf "%s%s%s%s%s" "%{$fg[cyan]%}[" "$elapsed_color" "$elapsed" "%{$fg[cyan]%}]" "$RETVAL") + unset last_run_time + fi + + if [ -z "$info" -a ! -z "$last_vcs_info" ]; then + custom_prompt="$last_vcs_info$base_prompt" + return; + fi + + if (( ${+VCS_PROMPT} )); then + last_vcs_info=$($VCS_PROMPT) + if [ ! -z "$last_vcs_info" ]; then + [ -z "$info" ] && info=$last_vcs_info || info="$info$last_vcs_info" + fi + fi + + [ -z "$info" ] && custom_prompt="$base_prompt" || custom_prompt="$info$base_prompt" +} + +function hg_prompt_info() { + unset output info parts branch_parts branch + + local output="" + if ! output="$(hg status 2> /dev/null)"; then + return + fi + + local info=$(hg log -l1 --template '{author}:{node|short}:{remotenames}:{phabdiff}') + local parts=(${(@s/:/)info}) + local branch_parts=(${(@s,/,)parts[3]}) + local branch=${branch_parts[-1]} + [ ! -z "${parts[3]}" ] && [[ "${parts[1]}" =~ "$USER@" ]] && branch=${parts[3]} + [ -z "${parts[3]}" ] && branch=${parts[2]} + + if [[ ! -z "$output" ]]; then + local color="%{$fg[red]%}" + elif [[ "${branch}" == "master" || "${branch}" == "warm" ]]; then + local color="%{$fg[yellow]%}" + else + local color="%{$fg[green]%}" + fi + + print "%{$fg[cyan]%}[${color}${branch}%{$fg[cyan]%}]" +} + +setopt PROMPT_SUBST +PROMPT='$custom_prompt' + + diff --git a/themes/gnzh.zsh-theme b/themes/gnzh.zsh-theme index 1e6c4e93b..ca62320e2 100644 --- a/themes/gnzh.zsh-theme +++ b/themes/gnzh.zsh-theme @@ -21,7 +21,7 @@ fi if [[ -n "$SSH_CLIENT" || -n "$SSH2_CLIENT" ]]; then PR_HOST='%F{red}%M%f' # SSH else - PR_HOST='%F{green}%M%f' # no SSH + PR_HOST='%F{green}%m%f' # no SSH fi diff --git a/themes/half-life.zsh-theme b/themes/half-life.zsh-theme index c4d785126..2ad84ac83 100644 --- a/themes/half-life.zsh-theme +++ b/themes/half-life.zsh-theme @@ -89,5 +89,9 @@ ZSH_THEME_RUBY_PROMPT_PREFIX="with%F{red} " ZSH_THEME_RUBY_PROMPT_SUFFIX="%{$reset_color%}" ZSH_THEME_RVM_PROMPT_OPTIONS="v g" +# virtualenv prompt settings +ZSH_THEME_VIRTUALENV_PREFIX=" with%F{red} " +ZSH_THEME_VIRTUALENV_SUFFIX="%{$reset_color%}" + setopt prompt_subst -PROMPT="${purple}%n%{$reset_color%} in ${limegreen}%~%{$reset_color%}\$(ruby_prompt_info)\$vcs_info_msg_0_${orange} λ%{$reset_color%} " +PROMPT="${purple}%n%{$reset_color%} in ${limegreen}%~%{$reset_color%}\$(virtualenv_prompt_info)\$(ruby_prompt_info)\$vcs_info_msg_0_${orange} λ%{$reset_color%} " diff --git a/themes/michelebologna.zsh-theme b/themes/michelebologna.zsh-theme index bb86d68db..b13b2caf1 100644 --- a/themes/michelebologna.zsh-theme +++ b/themes/michelebologna.zsh-theme @@ -29,14 +29,13 @@ local cyan="%{$fg_bold[cyan]%}" local yellow="%{$fg_bold[yellow]%}" local blue="%{$fg_bold[blue]%}" local magenta="%{$fg_bold[magenta]%}" -local white="%{$fg_bold[white]%}" local reset="%{$reset_color%}" local -a color_array -color_array=($green $red $cyan $yellow $blue $magenta $white) +color_array=($green $red $cyan $yellow $blue $magenta) -local username_color=$white -local hostname_color=$color_array[$[((#HOST))%7+1]] # choose hostname color based on first character +local username_color=$blue +local hostname_color=$color_array[$[((#HOST))%6+1]] # choose hostname color based on first character local current_dir_color=$blue local username="%n" @@ -66,10 +65,10 @@ function michelebologna_git_prompt { local out=$(git_prompt_info)$(git_prompt_status)$(git_remote_status) [[ -n $out ]] || return printf " %s(%s%s%s)%s" \ - "%{$fg_bold[white]%}" \ + "%{$fg_bold[blue]%}" \ "%{$fg_bold[green]%}" \ "$out" \ - "%{$fg_bold[white]%}" \ + "%{$fg_bold[blue]%}" \ "%{$reset_color%}" } diff --git a/themes/mlh.zsh-theme b/themes/mlh.zsh-theme index baff3fb63..c059bf850 100644 --- a/themes/mlh.zsh-theme +++ b/themes/mlh.zsh-theme @@ -47,6 +47,10 @@ if [ -z "$MLH_SHELL_SYMBOL" ]; then MLH_SHELL_SYMBOL="$ " fi +if [ -z "$MLH_SHELL_SYMBOL_ROOT" ]; then + MLH_SHELL_SYMBOL_ROOT="# " +fi + # colors USER_COLOR="%F{001}" DEVICE_COLOR="%F{033}" @@ -83,7 +87,11 @@ exit_code() { } prompt_end() { - printf "\n$MLH_SHELL_SYMBOL" + if [ "$UID" -eq 0 ]; then + printf "\n$MLH_SHELL_SYMBOL_ROOT" + else + printf "\n$MLH_SHELL_SYMBOL" + fi } # Set git_prompt_info text diff --git a/themes/mortalscumbag.zsh-theme b/themes/mortalscumbag.zsh-theme index d81a7ca06..36301cb76 100644 --- a/themes/mortalscumbag.zsh-theme +++ b/themes/mortalscumbag.zsh-theme @@ -51,8 +51,14 @@ function ssh_connection() { fi } +function _toolbox_prompt_info() { + if typeset -f toolbox_prompt_info > /dev/null; then + toolbox_prompt_info + fi +} + local ret_status="%(?:%{$fg_bold[green]%}:%{$fg_bold[red]%})%?%{$reset_color%}" -PROMPT=$'\n$(ssh_connection)%{$fg_bold[green]%}%n@%m%{$reset_color%}$(my_git_prompt) : %~\n[${ret_status}] %# ' +PROMPT=$'\n$(_toolbox_prompt_info)$(ssh_connection)%{$fg_bold[green]%}%n@%m%{$reset_color%}$(my_git_prompt) : %~\n[${ret_status}] %# ' ZSH_THEME_PROMPT_RETURNCODE_PREFIX="%{$fg_bold[red]%}" ZSH_THEME_GIT_PROMPT_PREFIX=" $fg[white]‹ %{$fg_bold[yellow]%}" diff --git a/themes/oldgallois.zsh-theme b/themes/oldgallois.zsh-theme new file mode 100644 index 000000000..bb97bfb17 --- /dev/null +++ b/themes/oldgallois.zsh-theme @@ -0,0 +1,24 @@ +# Depends on the git plugin for work_in_progress() +(( $+functions[work_in_progress] )) || work_in_progress() {} + +ZSH_THEME_GIT_PROMPT_PREFIX="%{$reset_color%}%{$fg[green]%}[" +ZSH_THEME_GIT_PROMPT_SUFFIX="]%{$reset_color%}" +ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[red]%}*%{$reset_color%}" +ZSH_THEME_GIT_PROMPT_CLEAN="" + +# Customized git status, oh-my-zsh currently does not allow render dirty status before branch +git_custom_status() { + local branch=$(git_current_branch) + [[ -n "$branch" ]] || return 0 + echo "$(parse_git_dirty)\ +%{${fg_bold[yellow]}%}$(work_in_progress)%{$reset_color%}\ +${ZSH_THEME_GIT_PROMPT_PREFIX}${branch}${ZSH_THEME_GIT_PROMPT_SUFFIX}" +} + +# RVM component of prompt +ZSH_THEME_RUBY_PROMPT_PREFIX="%{$fg[red]%}[" +ZSH_THEME_RUBY_PROMPT_SUFFIX="]%{$reset_color%}" + +# Combine it all into a final right-side prompt +RPS1="\$(git_custom_status)\$(ruby_prompt_info)${RPS1:+ $RPS1}" +PROMPT='%{$fg[cyan]%}[%~% ]%(?.%{$fg[green]%}.%{$fg[red]%})%B$%b ' diff --git a/themes/refined.zsh-theme b/themes/refined.zsh-theme index 5e2de7a87..2b55cfb0c 100644 --- a/themes/refined.zsh-theme +++ b/themes/refined.zsh-theme @@ -11,11 +11,11 @@ # more about both of these fantastic two people here: # # Sindre Sorhus -# Github: https://github.com/sindresorhus +# GitHub: https://github.com/sindresorhus # Twitter: https://twitter.com/sindresorhus # # Julien Nicoulaud -# Github: https://github.com/nicoulaj +# GitHub: https://github.com/nicoulaj # Twitter: https://twitter.com/nicoulaj # # ------------------------------------------------------------------------------ diff --git a/themes/robbyrussell.zsh-theme b/themes/robbyrussell.zsh-theme index 2fd5f2cdc..cfecfc892 100644 --- a/themes/robbyrussell.zsh-theme +++ b/themes/robbyrussell.zsh-theme @@ -1,7 +1,7 @@ -PROMPT="%(?:%{$fg_bold[green]%}➜ :%{$fg_bold[red]%}➜ )" -PROMPT+=' %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)' +PROMPT="%(?:%{$fg_bold[green]%}%1{➜%} :%{$fg_bold[red]%}%1{➜%} ) %{$fg[cyan]%}%c%{$reset_color%}" +PROMPT+=' $(git_prompt_info)' ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[blue]%}git:(%{$fg[red]%}" ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} " -ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[blue]%}) %{$fg[yellow]%}✗" +ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[blue]%}) %{$fg[yellow]%}%1{✗%}" ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg[blue]%})" diff --git a/tools/changelog.sh b/tools/changelog.sh index 6489a3cb2..3ad8fe786 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -106,6 +106,9 @@ function parse-commit { message="${match[1]}" # remove CR characters (might be inserted in GitHub UI commit description form) message="${message//$'\r'/}" + # remove lines containing only whitespace + local nlnl=$'\n\n' + message="${message//$'\n'[[:space:]]##$'\n'/$nlnl}" # skip next paragraphs (separated by two newlines or more) message="${message%%$'\n\n'*}" # ... and replace newlines with spaces @@ -157,6 +160,89 @@ function parse-commit { fi } +################################ +# SUPPORTS HYPERLINKS FUNCTION # +################################ + +# The code for checking if a terminal supports hyperlinks is copied from install.sh + +# The [ -t 1 ] check only works when the function is not called from +# a subshell (like in `$(...)` or `(...)`, so this hack redefines the +# function at the top level to always return false when stdout is not +# a tty. +if [ -t 1 ]; then + is_tty() { + true + } +else + is_tty() { + false + } +fi + +# This function uses the logic from supports-hyperlinks[1][2], which is +# made by Kat Marchán (@zkat) and licensed under the Apache License 2.0. +# [1] https://github.com/zkat/supports-hyperlinks +# [2] https://crates.io/crates/supports-hyperlinks +# +# Copyright (c) 2021 Kat Marchán +# +# 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. +supports_hyperlinks() { + # $FORCE_HYPERLINK must be set and be non-zero (this acts as a logic bypass) + if [ -n "$FORCE_HYPERLINK" ]; then + [ "$FORCE_HYPERLINK" != 0 ] + return $? + fi + + # If stdout is not a tty, it doesn't support hyperlinks + is_tty || return 1 + + # DomTerm terminal emulator (domterm.org) + if [ -n "$DOMTERM" ]; then + return 0 + fi + + # VTE-based terminals above v0.50 (Gnome Terminal, Guake, ROXTerm, etc) + if [ -n "$VTE_VERSION" ]; then + [ $VTE_VERSION -ge 5000 ] + return $? + fi + + # If $TERM_PROGRAM is set, these terminals support hyperlinks + case "$TERM_PROGRAM" in + Hyper|iTerm.app|terminology|WezTerm) return 0 ;; + esac + + # kitty supports hyperlinks + if [ "$TERM" = xterm-kitty ]; then + return 0 + fi + + # Windows Terminal also supports hyperlinks + if [ -n "$WT_SESSION" ]; then + return 0 + fi + + # Konsole supports hyperlinks, but it's an opt-in setting that can't be detected + # https://github.com/ohmyzsh/ohmyzsh/issues/10964 + # if [ -n "$KONSOLE_VERSION" ]; then + # return 0 + # fi + + return 1 +} + ############################# # RELEASE CHANGELOG DISPLAY # ############################# @@ -206,10 +292,17 @@ function display-release { function fmt:hash { #* Uses $hash from outer scope local hash="${1:-$hash}" + local short_hash="${hash:0:7}" # 7 characters sha, top level sha is 12 characters case "$output" in - raw) printf '%s' "$hash" ;; - text) printf '\e[33m%s\e[0m' "$hash" ;; # red - md) printf '[`%s`](https://github.com/ohmyzsh/ohmyzsh/commit/%s)' "$hash" ;; + raw) printf '%s' "$short_hash" ;; + text) + local text="\e[33m$short_hash\e[0m"; # red + if supports_hyperlinks; then + printf "\e]8;;%s\a%s\e]8;;\a" "https://github.com/ohmyzsh/ohmyzsh/commit/$hash" $text; + else + echo $text; + fi ;; + md) printf '[`%s`](https://github.com/ohmyzsh/ohmyzsh/commit/%s)' "$short_hash" "$hash" ;; esac } @@ -272,7 +365,12 @@ function display-release { case "$output" in raw) printf '%s' "$subject" ;; # In text mode, highlight (#) and dim text between `backticks` - text) sed -E $'s|#([0-9]+)|\e[32m#\\1\e[0m|g;s|`([^`]+)`|`\e[2m\\1\e[0m`|g' <<< "$subject" ;; + text) + if supports_hyperlinks; then + sed -E $'s|#([0-9]+)|\e]8;;https://github.com/ohmyzsh/ohmyzsh/issues/\\1\a\e[32m#\\1\e[0m\e]8;;\a|g;s|`([^`]+)`|`\e[2m\\1\e[0m`|g' <<< "$subject" + else + sed -E $'s|#([0-9]+)|\e[32m#\\1\e[0m|g;s|`([^`]+)`|`\e[2m\\1\e[0m`|g' <<< "$subject" + fi ;; # In markdown mode, link to (#) issues md) sed -E 's|#([0-9]+)|[#\1](https://github.com/ohmyzsh/ohmyzsh/issues/\1)|g' <<< "$subject" ;; esac @@ -415,13 +513,13 @@ function main { # Git log options # -z: commits are delimited by null bytes # --format: [7-char hash][ref names][subject][body] - # --abbrev=7: force commit hashes to be 7 characters long + # --abbrev=7: force commit hashes to be 12 characters long # --no-merges: merge commits are omitted # --first-parent: commits from merged branches are omitted local SEP="0mZmAgIcSeP" local -a raw_commits raw_commits=(${(0)"$(command git -c log.showSignature=false log -z \ - --format="%h${SEP}%D${SEP}%s${SEP}%b" --abbrev=7 \ + --format="%h${SEP}%D${SEP}%s${SEP}%b" --abbrev=12 \ --no-merges --first-parent $range)"}) local raw_commit diff --git a/tools/check_for_upgrade.sh b/tools/check_for_upgrade.sh index cc527e72d..1cc193bde 100644 --- a/tools/check_for_upgrade.sh +++ b/tools/check_for_upgrade.sh @@ -9,6 +9,7 @@ fi # - prompt (default): the user is asked before updating when it's time to update # - auto: the update is performed automatically when it's time # - reminder: a reminder is shown to the user when it's time to update +# - background-alpha: an experimental update-on-the-background option # - disabled: automatic update is turned off zstyle -s ':omz:update' mode update_mode || { update_mode=prompt @@ -21,10 +22,12 @@ zstyle -s ':omz:update' mode update_mode || { # Cancel update if: # - the automatic update is disabled. # - the current user doesn't have write permissions nor owns the $ZSH directory. +# - is not run from a tty # - git is unavailable on the system. if [[ "$update_mode" = disabled ]] \ || [[ ! -w "$ZSH" || ! -O "$ZSH" ]] \ - || ! command -v git &>/dev/null; then + || [[ ! -t 1 ]] \ + || ! command git --version 2>&1 >/dev/null; then unset update_mode return fi @@ -89,12 +92,37 @@ function is_update_available() { } function update_last_updated_file() { - echo "LAST_EPOCH=$(current_epoch)" >! "${ZSH_CACHE_DIR}/.zsh-update" + local exit_status="$1" error="$2" + + if [[ -z "${1}${2}" ]]; then + echo "LAST_EPOCH=$(current_epoch)" >! "${ZSH_CACHE_DIR}/.zsh-update" + return + fi + + cat >! "${ZSH_CACHE_DIR}/.zsh-update" <&1); then + update_last_updated_file 0 "Update successful" + else + exit_status=$? + update_last_updated_file $exit_status "$error" + return $exit_status fi } @@ -123,87 +151,145 @@ function has_typed_input() { } } -() { - emulate -L zsh +function handle_update() { + () { + emulate -L zsh - local epoch_target mtime option LAST_EPOCH + local epoch_target mtime option LAST_EPOCH - # Remove lock directory if older than a day - zmodload zsh/datetime - zmodload -F zsh/stat b:zstat - if mtime=$(zstat +mtime "$ZSH/log/update.lock" 2>/dev/null); then - if (( (mtime + 3600 * 24) < EPOCHSECONDS )); then - command rm -rf "$ZSH/log/update.lock" + # Remove lock directory if older than a day + zmodload zsh/datetime + zmodload -F zsh/stat b:zstat + if mtime=$(zstat +mtime "$ZSH/log/update.lock" 2>/dev/null); then + if (( (mtime + 3600 * 24) < EPOCHSECONDS )); then + command rm -rf "$ZSH/log/update.lock" + fi fi - fi - # Check for lock directory - if ! command mkdir "$ZSH/log/update.lock" 2>/dev/null; then - return - fi + # Check for lock directory + if ! command mkdir "$ZSH/log/update.lock" 2>/dev/null; then + return + fi - # Remove lock directory on exit. `return $ret` is important for when trapping a SIGINT: - # The return status from the function is handled specially. If it is zero, the signal is - # assumed to have been handled, and execution continues normally. Otherwise, the shell - # will behave as interrupted except that the return status of the trap is retained. - # This means that for a CTRL+C, the trap needs to return the same exit status so that - # the shell actually exits what it's running. - trap " - ret=\$? - unset update_mode - unset -f current_epoch is_update_available update_last_updated_file update_ohmyzsh 2>/dev/null - command rm -rf '$ZSH/log/update.lock' - return \$ret - " EXIT INT QUIT + # Remove lock directory on exit. `return $ret` is important for when trapping a SIGINT: + # The return status from the function is handled specially. If it is zero, the signal is + # assumed to have been handled, and execution continues normally. Otherwise, the shell + # will behave as interrupted except that the return status of the trap is retained. + # This means that for a CTRL+C, the trap needs to return the same exit status so that + # the shell actually exits what it's running. + trap " + ret=\$? + unset update_mode + unset -f current_epoch is_update_available update_last_updated_file update_ohmyzsh handle_update 2>/dev/null + command rm -rf '$ZSH/log/update.lock' + return \$ret + " EXIT INT QUIT - # Create or update .zsh-update file if missing or malformed - if ! source "${ZSH_CACHE_DIR}/.zsh-update" 2>/dev/null || [[ -z "$LAST_EPOCH" ]]; then - update_last_updated_file - return - fi + # Create or update .zsh-update file if missing or malformed + if ! source "${ZSH_CACHE_DIR}/.zsh-update" 2>/dev/null || [[ -z "$LAST_EPOCH" ]]; then + update_last_updated_file + return + fi - # Number of days before trying to update again - zstyle -s ':omz:update' frequency epoch_target || epoch_target=${UPDATE_ZSH_DAYS:-13} - # Test if enough time has passed until the next update - if (( ( $(current_epoch) - $LAST_EPOCH ) < $epoch_target )); then - return - fi + # Number of days before trying to update again + zstyle -s ':omz:update' frequency epoch_target || epoch_target=${UPDATE_ZSH_DAYS:-13} + # Test if enough time has passed until the next update + if (( ( $(current_epoch) - $LAST_EPOCH ) < $epoch_target )); then + return + fi - # Test if Oh My Zsh directory is a git repository - if ! (builtin cd -q "$ZSH" && LANG= git rev-parse &>/dev/null); then - echo >&2 "[oh-my-zsh] Can't update: not a git repository." - return - fi + # Test if Oh My Zsh directory is a git repository + if ! (builtin cd -q "$ZSH" && LANG= git rev-parse &>/dev/null); then + echo >&2 "[oh-my-zsh] Can't update: not a git repository." + return + fi - # Check if there are updates available before proceeding - if ! is_update_available; then - return - fi + # Check if there are updates available before proceeding + if ! is_update_available; then + update_last_updated_file + return + fi - # If in reminder mode or user has typed input, show reminder and exit - if [[ "$update_mode" = reminder ]] || has_typed_input; then - printf '\r\e[0K' # move cursor to first column and clear whole line - echo "[oh-my-zsh] It's time to update! You can do that by running \`omz update\`" - return 0 - fi + # If in reminder mode or user has typed input, show reminder and exit + if [[ "$update_mode" = reminder ]] || { [[ "$update_mode" != background-alpha ]] && has_typed_input }; then + printf '\r\e[0K' # move cursor to first column and clear whole line + echo "[oh-my-zsh] It's time to update! You can do that by running \`omz update\`" + return 0 + fi - # Don't ask for confirmation before updating if in auto mode - if [[ "$update_mode" = auto ]]; then - update_ohmyzsh - return $? - fi + # Don't ask for confirmation before updating if in auto mode + if [[ "$update_mode" = (auto|background-alpha) ]]; then + update_ohmyzsh + return $? + fi - # Ask for confirmation and only update on 'y', 'Y' or Enter - # Otherwise just show a reminder for how to update - echo -n "[oh-my-zsh] Would you like to update? [Y/n] " - read -r -k 1 option - [[ "$option" = $'\n' ]] || echo - case "$option" in - [yY$'\n']) update_ohmyzsh ;; - [nN]) update_last_updated_file ;& - *) echo "[oh-my-zsh] You can update manually by running \`omz update\`" ;; - esac + # Ask for confirmation and only update on 'y', 'Y' or Enter + # Otherwise just show a reminder for how to update + echo -n "[oh-my-zsh] Would you like to update? [Y/n] " + read -r -k 1 option + [[ "$option" = $'\n' ]] || echo + case "$option" in + [yY$'\n']) update_ohmyzsh ;; + [nN]) update_last_updated_file ;& + *) echo "[oh-my-zsh] You can update manually by running \`omz update\`" ;; + esac + } + + unset update_mode + unset -f current_epoch is_update_available update_last_updated_file update_ohmyzsh handle_update } -unset update_mode -unset -f current_epoch is_update_available update_last_updated_file update_ohmyzsh +case "$update_mode" in + background-alpha) + autoload -Uz add-zsh-hook + + _omz_bg_update() { + # do the update in a subshell + (handle_update) &| + + # register update results function + add-zsh-hook precmd _omz_bg_update_status + + # deregister background function + add-zsh-hook -d precmd _omz_bg_update + unset -f _omz_bg_update + } + + _omz_bg_update_status() { + { + local LAST_EPOCH EXIT_STATUS ERROR + if [[ ! -f "$ZSH_CACHE_DIR"/.zsh-update ]]; then + return 1 + fi + + # check update results until timeout is reached + . "$ZSH_CACHE_DIR/.zsh-update" + if [[ -z "$EXIT_STATUS" || -z "$ERROR" ]]; then + return 1 + fi + + if [[ "$EXIT_STATUS" -eq 0 ]]; then + print -P "\n%F{green}[oh-my-zsh] Update successful.%f" + return 0 + elif [[ "$EXIT_STATUS" -ne 0 ]]; then + print -P "\n%F{red}[oh-my-zsh] There was an error updating:%f" + printf "\n${fg[yellow]}%s${reset_color}" "$ERROR" + return 0 + fi + } always { + if (( TRY_BLOCK_ERROR == 0 )); then + # if last update results have been handled, remove them from the status file + update_last_updated_file + + # deregister background function + add-zsh-hook -d precmd _omz_bg_update_status + unset -f _omz_bg_update_status + fi + } + } + + add-zsh-hook precmd _omz_bg_update + ;; + *) + handle_update ;; +esac diff --git a/tools/install.sh b/tools/install.sh index 495ad2c11..508fc2f77 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -16,6 +16,9 @@ # ZSH=~/.zsh sh install.sh # # Respects the following environment variables: +# ZDOTDIR - path to Zsh dotfiles directory (default: unset). See [1][2] +# [1] https://zsh.sourceforge.io/Doc/Release/Parameters.html#index-ZDOTDIR +# [2] https://zsh.sourceforge.io/Doc/Release/Files.html#index-ZDOTDIR_002c-use-of # ZSH - path to the Oh My Zsh repository folder (default: $HOME/.oh-my-zsh) # REPO - name of the GitHub repo to install from (default: ohmyzsh/ohmyzsh) # REMOTE - full remote URL of the git repo to install (default: GitHub via HTTPS) @@ -53,8 +56,19 @@ HOME="${HOME:-$(eval echo ~$USER)}" # Track if $ZSH was provided custom_zsh=${ZSH:+yes} -# Default settings +# Use $zdot to keep track of where the directory is for zsh dotfiles +# To check if $ZDOTDIR was provided, explicitly check for $ZDOTDIR +zdot="${ZDOTDIR:-$HOME}" + +# Default value for $ZSH +# a) if $ZDOTDIR is supplied and not $HOME: $ZDOTDIR/ohmyzsh +# b) otherwise, $HOME/.oh-my-zsh +if [ -n "$ZDOTDIR" ] && [ "$ZDOTDIR" != "$HOME" ]; then + ZSH="${ZSH:-$ZDOTDIR/ohmyzsh}" +fi ZSH="${ZSH:-$HOME/.oh-my-zsh}" + +# Default settings REPO=${REPO:-ohmyzsh/ohmyzsh} REMOTE=${REMOTE:-https://github.com/${REPO}.git} BRANCH=${BRANCH:-master} @@ -72,6 +86,10 @@ command_exists() { user_can_sudo() { # Check if sudo is installed command_exists sudo || return 1 + # Termux can't run sudo, so we can detect it and exit the function early. + case "$PREFIX" in + *com.termux*) return 1 ;; + esac # The following command has 3 parts: # # 1. Run `sudo` with `-v`. Does the following: @@ -156,11 +174,17 @@ supports_hyperlinks() { return 0 fi - # Windows Terminal or Konsole also support hyperlinks - if [ -n "$WT_SESSION" ] || [ -n "$KONSOLE_VERSION" ]; then + # Windows Terminal also supports hyperlinks + if [ -n "$WT_SESSION" ]; then return 0 fi + # Konsole supports hyperlinks, but it's an opt-in setting that can't be detected + # https://github.com/ohmyzsh/ohmyzsh/issues/10964 + # if [ -n "$KONSOLE_VERSION" ]; then + # return 0 + # fi + return 1 } @@ -185,7 +209,7 @@ supports_truecolor() { fmt_link() { # $1: text, $2: url, $3: fallback mode if supports_hyperlinks; then - printf '\033]8;;%s\a%s\033]8;;\a\n' "$2" "$1" + printf '\033]8;;%s\033\\%s\033]8;;\033\\\n' "$2" "$1" return fi @@ -267,7 +291,7 @@ setup_ohmyzsh() { } ostype=$(uname) - if [ -z "${ostype%CYGWIN*}" ] && git --version | grep -q msysgit; then + if [ -z "${ostype%CYGWIN*}" ] && git --version | grep -Eq 'msysgit|windows'; then fmt_error "Windows/MSYS Git is not supported on Cygwin" fmt_error "Make sure the Cygwin git package is installed and is first on the \$PATH" exit 1 @@ -305,11 +329,11 @@ setup_zshrc() { echo "${FMT_BLUE}Looking for an existing zsh config...${FMT_RESET}" # Must use this exact name so uninstall.sh can find it - OLD_ZSHRC=~/.zshrc.pre-oh-my-zsh - if [ -f ~/.zshrc ] || [ -h ~/.zshrc ]; then + OLD_ZSHRC="$zdot/.zshrc.pre-oh-my-zsh" + if [ -f "$zdot/.zshrc" ] || [ -h "$zdot/.zshrc" ]; then # Skip this if the user doesn't want to replace an existing .zshrc if [ "$KEEP_ZSHRC" = yes ]; then - echo "${FMT_YELLOW}Found ~/.zshrc.${FMT_RESET} ${FMT_GREEN}Keeping...${FMT_RESET}" + echo "${FMT_YELLOW}Found ${zdot}/.zshrc.${FMT_RESET} ${FMT_GREEN}Keeping...${FMT_RESET}" return fi if [ -e "$OLD_ZSHRC" ]; then @@ -321,19 +345,24 @@ setup_zshrc() { fi mv "$OLD_ZSHRC" "${OLD_OLD_ZSHRC}" - echo "${FMT_YELLOW}Found old ~/.zshrc.pre-oh-my-zsh." \ + echo "${FMT_YELLOW}Found old .zshrc.pre-oh-my-zsh." \ "${FMT_GREEN}Backing up to ${OLD_OLD_ZSHRC}${FMT_RESET}" fi - echo "${FMT_YELLOW}Found ~/.zshrc.${FMT_RESET} ${FMT_GREEN}Backing up to ${OLD_ZSHRC}${FMT_RESET}" - mv ~/.zshrc "$OLD_ZSHRC" + echo "${FMT_YELLOW}Found ${zdot}/.zshrc.${FMT_RESET} ${FMT_GREEN}Backing up to ${OLD_ZSHRC}${FMT_RESET}" + mv "$zdot/.zshrc" "$OLD_ZSHRC" fi - echo "${FMT_GREEN}Using the Oh My Zsh template file and adding it to ~/.zshrc.${FMT_RESET}" + echo "${FMT_GREEN}Using the Oh My Zsh template file and adding it to $zdot/.zshrc.${FMT_RESET}" - # Replace $HOME path with '$HOME' in $ZSH variable in .zshrc file - omz=$(echo "$ZSH" | sed "s|^$HOME/|\$HOME/|") - sed "s|^export ZSH=.*$|export ZSH=\"${omz}\"|" "$ZSH/templates/zshrc.zsh-template" > ~/.zshrc-omztemp - mv -f ~/.zshrc-omztemp ~/.zshrc + # Modify $ZSH variable in .zshrc directory to use the literal $ZDOTDIR or $HOME + omz="$ZSH" + if [ -n "$ZDOTDIR" ] && [ "$ZDOTDIR" != "$HOME" ]; then + omz=$(echo "$omz" | sed "s|^$ZDOTDIR/|\$ZDOTDIR/|") + fi + omz=$(echo "$omz" | sed "s|^$HOME/|\$HOME/|") + + sed "s|^export ZSH=.*$|export ZSH=\"${omz}\"|" "$ZSH/templates/zshrc.zsh-template" > "$zdot/.zshrc-omztemp" + mv -f "$zdot/.zshrc-omztemp" "$zdot/.zshrc" echo } @@ -401,9 +430,9 @@ EOF # We're going to change the default shell, so back up the current one if [ -n "$SHELL" ]; then - echo "$SHELL" > ~/.shell.pre-oh-my-zsh + echo "$SHELL" > "$zdot/.shell.pre-oh-my-zsh" else - grep "^$USER:" /etc/passwd | awk -F: '{print $7}' > ~/.shell.pre-oh-my-zsh + grep "^$USER:" /etc/passwd | awk -F: '{print $7}' > "$zdot/.shell.pre-oh-my-zsh" fi echo "Changing your shell to $zsh..." @@ -445,7 +474,7 @@ print_success() { printf '\n' printf '\n' printf "%s %s %s\n" "Before you scream ${FMT_BOLD}${FMT_YELLOW}Oh My Zsh!${FMT_RESET} look over the" \ - "$(fmt_code "$(fmt_link ".zshrc" "file://$HOME/.zshrc" --text)")" \ + "$(fmt_code "$(fmt_link ".zshrc" "file://$zdot/.zshrc" --text)")" \ "file to select plugins, themes, and options." printf '\n' printf '%s\n' "• Follow us on Twitter: $(fmt_link @ohmyzsh https://twitter.com/ohmyzsh)" @@ -500,6 +529,11 @@ EOF exit 1 fi + # Create ZDOTDIR folder structure if it doesn't exist + if [ -n "$ZDOTDIR" ]; then + mkdir -p "$ZDOTDIR" + fi + setup_ohmyzsh setup_zshrc setup_shell diff --git a/tools/require_tool.sh b/tools/require_tool.sh index 1fa77f77a..19c5f6fa9 100755 --- a/tools/require_tool.sh +++ b/tools/require_tool.sh @@ -107,7 +107,7 @@ usage() { NAME require_tool.sh - Ensure version of a tool is greater than the one expected -SYNOPSYS +SYNOPSIS require_tool.sh [ -h ] [ --help ] [ TOOL MIN_VERSION ] diff --git a/tools/uninstall.sh b/tools/uninstall.sh index 6a0e7b4c7..6e3df7aca 100644 --- a/tools/uninstall.sh +++ b/tools/uninstall.sh @@ -1,3 +1,15 @@ +if hash chsh >/dev/null 2>&1 && [ -f ~/.shell.pre-oh-my-zsh ]; then + old_shell=$(cat ~/.shell.pre-oh-my-zsh) + echo "Switching your shell back to '$old_shell':" + if chsh -s "$old_shell"; then + rm -f ~/.shell.pre-oh-my-zsh + else + echo "Could not change default shell. Change it manually by running chsh" + echo "or editing the /etc/passwd file." + exit + fi +fi + read -r -p "Are you sure you want to remove Oh My Zsh? [y/N] " confirmation if [ "$confirmation" != y ] && [ "$confirmation" != Y ]; then echo "Uninstall cancelled" @@ -25,16 +37,5 @@ else echo "No original zsh config found" fi -if hash chsh >/dev/null 2>&1 && [ -f ~/.shell.pre-oh-my-zsh ]; then - old_shell=$(cat ~/.shell.pre-oh-my-zsh) - echo "Switching your shell back to '$old_shell':" - if chsh -s "$old_shell"; then - rm -f ~/.shell.pre-oh-my-zsh - else - echo "Could not change default shell. Change it manually by running chsh" - echo "or editing the /etc/passwd file." - fi -fi - echo "Thanks for trying out Oh My Zsh. It's been uninstalled." echo "Don't forget to restart your terminal!" diff --git a/tools/upgrade.sh b/tools/upgrade.sh index afc6a98dd..f7a263d66 100755 --- a/tools/upgrade.sh +++ b/tools/upgrade.sh @@ -1,4 +1,7 @@ #!/usr/bin/env zsh +set +u # disable nounset + +local ret=0 # exit code # Protect against running with shells other than zsh if [ -z "$ZSH_VERSION" ]; then @@ -12,6 +15,23 @@ esac cd "$ZSH" +verbose_mode="default" +interactive=false + +while getopts "v:i" opt; do + case $opt in + v) + if [[ $OPTARG == default || $OPTARG == minimal || $OPTARG == silent ]]; then + verbose_mode=$OPTARG + else + echo "[oh-my-zsh] update verbosity '$OPTARG' is not valid" + echo "[oh-my-zsh] valid options are 'default', 'minimal' and 'silent'" + fi + ;; + i) interactive=true ;; + esac +done + # Use colors, but only if connected to a terminal # and that terminal supports them. @@ -78,11 +98,17 @@ supports_hyperlinks() { return 0 fi - # Windows Terminal or Konsole also support hyperlinks - if [ -n "$WT_SESSION" ] || [ -n "$KONSOLE_VERSION" ]; then + # Windows Terminal also supports hyperlinks + if [ -n "$WT_SESSION" ]; then return 0 fi + # Konsole supports hyperlinks, but it's an opt-in setting that can't be detected + # https://github.com/ohmyzsh/ohmyzsh/issues/10964 + # if [ -n "$KONSOLE_VERSION" ]; then + # return 0 + # fi + return 1 } @@ -107,7 +133,7 @@ supports_truecolor() { fmt_link() { # $1: text, $2: url, $3: fallback mode if supports_hyperlinks; then - printf '\033]8;;%s\a%s\033]8;;\a\n' "$2" "$1" + printf '\033]8;;%s\033\\%s\033]8;;\033\\\n' "$2" "$1" return fi @@ -158,17 +184,23 @@ fi # Update upstream remote to ohmyzsh org git remote -v | while read remote url extra; do case "$url" in - https://github.com/robbyrussell/oh-my-zsh(|.git)) - git remote set-url "$remote" "https://github.com/ohmyzsh/ohmyzsh.git" - break ;; - git@github.com:robbyrussell/oh-my-zsh(|.git)) - git remote set-url "$remote" "git@github.com:ohmyzsh/ohmyzsh.git" - break ;; - # Update out-of-date "unauthenticated git protocol on port 9418" to https git://github.com/robbyrussell/oh-my-zsh(|.git)) - git remote set-url "$remote" "https://github.com/ohmyzsh/ohmyzsh.git" - break ;; + # Update out-of-date "unauthenticated git protocol on port 9418" to https + git remote set-url "$remote" "https://github.com/ohmyzsh/ohmyzsh.git" ;; + https://github.com/robbyrussell/oh-my-zsh(|.git)) + git remote set-url "$remote" "https://github.com/ohmyzsh/ohmyzsh.git" ;; + git@github.com:robbyrussell/oh-my-zsh(|.git)) + git remote set-url "$remote" "git@github.com:ohmyzsh/ohmyzsh.git" ;; + https://github.com/ohmyzsh/ohmyzsh(|.git)) ;; + git@github.com:ohmyzsh/ohmyzsh(|.git)) ;; + *) continue ;; esac + + # If we reach this point we have found the proper ohmyzsh upstream remote. If we don't, + # we'll only update from the set remote if `oh-my-zsh.remote` has been set to a remote, + # as when installing from a fork. + git config --local oh-my-zsh.remote "$remote" + break done # Set git-config values known to fix git errors @@ -197,7 +229,9 @@ git checkout -q "$branch" -- || exit 1 last_commit=$(git rev-parse "$branch") # Update Oh My Zsh -printf "${BLUE}%s${RESET}\n" "Updating Oh My Zsh" +if [[ $verbose_mode != silent ]]; then + printf "${BLUE}%s${RESET}\n" "Updating Oh My Zsh" +fi if LANG= git pull --quiet --rebase $remote $branch; then # Check if it was really updated or not if [[ "$(git rev-parse HEAD)" = "$last_commit" ]]; then @@ -209,24 +243,30 @@ if LANG= git pull --quiet --rebase $remote $branch; then git config oh-my-zsh.lastVersion "$last_commit" # Print changelog to the terminal - if [[ "$1" = --interactive ]]; then + if [[ $interactive == true && $verbose_mode == default ]]; then "$ZSH/tools/changelog.sh" HEAD "$last_commit" fi - printf "${BLUE}%s \`${BOLD}%s${RESET}${BLUE}\`${RESET}\n" "You can see the changelog with" "omz changelog" + if [[ $verbose_mode != silent ]]; then + printf "${BLUE}%s \`${BOLD}%s${RESET}${BLUE}\`${RESET}\n" "You can see the changelog with" "omz changelog" + fi fi - printf '%s %s__ %s %s %s %s %s__ %s\n' $RAINBOW $RESET - printf '%s ____ %s/ /_ %s ____ ___ %s__ __ %s ____ %s_____%s/ /_ %s\n' $RAINBOW $RESET - printf '%s / __ \\%s/ __ \\ %s / __ `__ \\%s/ / / / %s /_ / %s/ ___/%s __ \\ %s\n' $RAINBOW $RESET - printf '%s/ /_/ /%s / / / %s / / / / / /%s /_/ / %s / /_%s(__ )%s / / / %s\n' $RAINBOW $RESET - printf '%s\\____/%s_/ /_/ %s /_/ /_/ /_/%s\\__, / %s /___/%s____/%s_/ /_/ %s\n' $RAINBOW $RESET - printf '%s %s %s %s /____/ %s %s %s %s\n' $RAINBOW $RESET - printf '\n' - printf "${BLUE}%s${RESET}\n\n" "$message" - printf "${BLUE}${BOLD}%s %s${RESET}\n" "To keep up with the latest news and updates, follow us on Twitter:" "$(fmt_link @ohmyzsh https://twitter.com/ohmyzsh)" - printf "${BLUE}${BOLD}%s %s${RESET}\n" "Want to get involved in the community? Join our Discord:" "$(fmt_link "Discord server" https://discord.gg/ohmyzsh)" - printf "${BLUE}${BOLD}%s %s${RESET}\n" "Get your Oh My Zsh swag at:" "$(fmt_link "Planet Argon Shop" https://shop.planetargon.com/collections/oh-my-zsh)" + if [[ $verbose_mode == default ]]; then + printf '%s %s__ %s %s %s %s %s__ %s\n' $RAINBOW $RESET + printf '%s ____ %s/ /_ %s ____ ___ %s__ __ %s ____ %s_____%s/ /_ %s\n' $RAINBOW $RESET + printf '%s / __ \\%s/ __ \\ %s / __ `__ \\%s/ / / / %s /_ / %s/ ___/%s __ \\ %s\n' $RAINBOW $RESET + printf '%s/ /_/ /%s / / / %s / / / / / /%s /_/ / %s / /_%s(__ )%s / / / %s\n' $RAINBOW $RESET + printf '%s\\____/%s_/ /_/ %s /_/ /_/ /_/%s\\__, / %s /___/%s____/%s_/ /_/ %s\n' $RAINBOW $RESET + printf '%s %s %s %s /____/ %s %s %s %s\n' $RAINBOW $RESET + printf '\n' + printf "${BLUE}%s${RESET}\n\n" "$message" + printf "${BLUE}${BOLD}%s %s${RESET}\n" "To keep up with the latest news and updates, follow us on Twitter:" "$(fmt_link @ohmyzsh https://twitter.com/ohmyzsh)" + printf "${BLUE}${BOLD}%s %s${RESET}\n" "Want to get involved in the community? Join our Discord:" "$(fmt_link "Discord server" https://discord.gg/ohmyzsh)" + printf "${BLUE}${BOLD}%s %s${RESET}\n" "Get your Oh My Zsh swag at:" "$(fmt_link "Planet Argon Shop" https://shop.planetargon.com/collections/oh-my-zsh)" + elif [[ $verbose_mode == minimal ]]; then + printf "${BLUE}%s${RESET}\n" "$message" + fi else ret=$? printf "${RED}%s${RESET}\n" 'There was an error updating. Try again later?'