Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The best way to add .oh-my-zsh plugins that don't have a repo #1614

Closed
3 tasks done
jaron-l opened this issue Nov 11, 2021 · 18 comments
Closed
3 tasks done

The best way to add .oh-my-zsh plugins that don't have a repo #1614

jaron-l opened this issue Nov 11, 2021 · 18 comments
Labels
support Support request

Comments

@jaron-l
Copy link

jaron-l commented Nov 11, 2021

What exactly are you trying to do?

Several command line tools provide ways to add command completions to ZSH but don't provide a static file that can be integrated into .chezmoiexternal.toml using either external repo configuration. For example, in order to add bitwarden command completions to zsh through .oh-my-zsh, you have to run the following command to generate the completion file1:

mkdir $ZSH_CUSTOM/plugins/bw
bw completion --shell zsh | sudo tee $ZSH_CUSTOM/plugins/bw/_bw

Because I don't see a place where this file exists statically (it looks like it's being rendered), I need a way to include it through a different means.

What have you tried so far?

My first thought was to just include it like a normal file in chezmoi. So I ran:

chezmoi add $ZSH_CUSTOM/plugins/bw --recursive

after having already run the bw completion command to generate the file. The problem here is that the file gets added to chezmoi's repo at the base level, i.e. $(chezmoi source-path)/plugins/bw/_bw, which is not the correct position to be installed in for .oh-my-zsh to pick it up. Perhaps this is because .oh-my-zsh is in the .chezmoiexternal.toml? The effect is that chezmoi apply or using chezmoi on another machine causes _bw to be pull into $HOME/plugins/bw/_bw and for the plugin to not be loaded.

Where else have you checked for solutions?

Output of any commands you've tried with --verbose flag

❯ chezmoi add --verbose $ZSH_CUSTOM/plugins/bw --recursive
diff --git a/exact_plugins/bw b/exact_plugins/bw
new file mode 40755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
--- /dev/null
+++ b/exact_plugins/bw
diff --git a/exact_plugins/bw/_bw b/exact_plugins/bw/_bw
new file mode 100644
index 0000000000000000000000000000000000000000..69beaf6e3ba428bb6ca66c005f6af743c804d972
--- /dev/null
+++ b/exact_plugins/bw/_bw
@@ -0,0 +1,414 @@
+#compdef _bw bw
+
+function _bw {
... ( a bunch of other output of the contents of the file that I feel is impertinent to this issue)

and the subsequent chezmoi diff

❯ chezmoi diff --verbose
diff --git a/.oh-my-zsh/custom/plugins/bw b/.oh-my-zsh/custom/plugins/bw
deleted file mode 40755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
--- a/.oh-my-zsh/custom/plugins/bw
+++ /dev/null
diff --git a/.oh-my-zsh/custom/plugins/gh b/.oh-my-zsh/custom/plugins/gh
deleted file mode 40755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
--- a/.oh-my-zsh/custom/plugins/gh
+++ /dev/null
diff --git a/.oh-my-zsh/custom/plugins/poetry b/.oh-my-zsh/custom/plugins/poetry
deleted file mode 40755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
--- a/.oh-my-zsh/custom/plugins/poetry
+++ /dev/null
diff --git a/plugins b/plugins
new file mode 40755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
--- /dev/null
+++ b/plugins
diff --git a/plugins/bw b/plugins/bw
new file mode 40755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
--- /dev/null
+++ b/plugins/bw
diff --git a/plugins/bw/_bw b/plugins/bw/_bw
new file mode 100644
index 0000000000000000000000000000000000000000..69beaf6e3ba428bb6ca66c005f6af743c804d972
--- /dev/null
+++ b/plugins/bw/_bw
@@ -0,0 +1,414 @@
+#compdef _bw bw
+
... cut for brevity ...
+function _bw_receive {
+  _arguments -C \
+    '--password[Password needed to access the Send.]' \
+    '--passwordenv[Environment variable storing the Send'"'"'s password]' \
+    '--passwordfile[Path to a file containing the Sends password as its first line]' \
+    '--obj[Return the Send'"'"'s json object rather than the Send's content]' \
+    '--output[Specify a file path to save a File-type Send to]' \
+    '(-h --help)'{-h,--help}'[output usage information]' \
+    "*::arg:->args"
+}
\ No newline at end of file
diff --git a/plugins/gh b/plugins/gh
new file mode 40755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
--- /dev/null
+++ b/plugins/gh
diff --git a/plugins/gh/_gh b/plugins/gh/_gh
new file mode 100644
index 0000000000000000000000000000000000000000..dfce760b6c84c509d4fe1c67e888dd2f38dcacc3
--- /dev/null
+++ b/plugins/gh/_gh
@@ -0,0 +1,177 @@
+#compdef _gh gh
+
.. cut for brevity ...
+# don't run the completion function when being source-ed or eval-ed
+if [ "$funcstack[1]" = "_gh" ]; then
+	_gh
+fi
diff --git a/plugins/poetry b/plugins/poetry
new file mode 40755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
--- /dev/null
+++ b/plugins/poetry
diff --git a/plugins/poetry/_poetry b/plugins/poetry/_poetry
new file mode 100644
index 0000000000000000000000000000000000000000..b297e88d38907f7b28d09bbdfa8d8c806a48c13b
--- /dev/null
+++ b/plugins/poetry/_poetry
@@ -0,0 +1,135 @@
+#compdef poetry
+
... cut for brevity...
+_poetry_0083e2c55c594e6f_complete "$@"
+compdef _poetry_0083e2c55c594e6f_complete /home/lund/.local/share/pypoetry/venv/bin/poetry

Output of chezmoi doctor

❯ chezmoi doctor --verbose
RESULT   CHECK                MESSAGE
ok       version              v2.7.5, commit 53bb61524468afe3262d6d8089fdc6912dbccb34, built at 2021-11-07T21:20:58Z, built by goreleaser
ok       os-arch              linux/amd64 (Ubuntu 20.04.3 LTS (Focal Fossa))
ok       executable           /snap/chezmoi/307/chezmoi
ok       config-file          no config file found
ok       source-dir           ~/.local/share/chezmoi is a directory
ok       suspicious-entries   no suspicious entries
ok       working-tree         ~/.local/share/chezmoi is a directory
ok       dest-dir             ~ is a directory
ok       shell                found /bin/bash
ok       edit-command         found /usr/bin/vim
ok       umask                022
ok       git-command          found /usr/bin/git, version 2.25.1
ok       merge-command        found /usr/bin/vimdiff
ok       age-command          age not found in $PATH
ok       gpg-command          found /usr/bin/gpg, version 2.2.19
info     pinentry-command     not set
info     1password-command    op not found in $PATH
failed   bitwarden-command    found /snap/bin/bw, could not parse version from Warning: Ignoring extra certs from `/usr/local/share/ca-certificates/dyneticsroot.crt`, load failed: error:02001002:system library:fopen:No such file or directory
1.19.1
info   gopass-command      gopass not found in $PATH
info   keepassxc-command   keepassxc-cli not found in $PATH
info   keepassxc-db        not set
info   lastpass-command    lpass not found in $PATH
info   pass-command        pass not found in $PATH
info   vault-command       vault not found in $PATH
info   secret-command      not set

Additional context

I'm pretty sure you can ignore the bitwarden error shown in chezmoi doctor as I have the snap installed which has some permission issues accessing a certificate. Seeing as I'm not currently using bitwarden for this setup, I don't think it affects this issue.

@felipecrs
Copy link
Contributor

felipecrs commented Nov 11, 2021

This is a very interesting use case. You can probably make use of the output template function though. Something like:

$ cat ~/.local/share/chezmoi/zsh-custom-folder/plugins/bw/_bw.tmpl
{{ output "bw" "completion" "--shell" "zsh" }}

I didn't test it, but it should work. Now I'm thinking on doing it in my dotfiles too!

@jaron-l
Copy link
Author

jaron-l commented Nov 11, 2021

This is a very interesting use case. You can probably make use of the output template function though. Something like:

$ cat ~/.local/share/chezmoi/zsh-custom-folder/plugins/bw/_bw.tmpl
{{ output "bw" "completion" "--shell" "zsh" }}

I didn't test it, but it should work. Now I'm thinking on doing it in my dotfiles too!

That's a very useful tip, but the thing I am most struggling with is why the actual file is being put in the wrong place. I am currently fine with adding the file as is once, i.e. in it's current state or not being generated, but I cannot add the file at all and have it be put in the correct path.

@felipecrs
Copy link
Contributor

felipecrs commented Nov 11, 2021

Ops, I forgot executable_ prefix, btw. This is required for ZSH completions. So, it should be:

<your-zsh-custom-folder-in-dotfiles-repo>/plugins/bw/executable__bw.tmpl

PS: literal_ may be needed because of the underscore: <your-zsh-custom-folder-in-dotfiles-repo>/plugins/bw/executable_literal__bw.tmpl

@felipecrs
Copy link
Contributor

I am currently fine with adding the file as is once, i.e. in it's current state or not being generated, but I cannot add the file at all and have it be put in the correct path.

Hm... what's the real path for the file? (in other words, what is the current contents of $ZSH_CUSTOM for you?)

@felipecrs
Copy link
Contributor

felipecrs commented Nov 11, 2021

I got your point now. Can you try to create the correct folder structure in your $(chezmoi source-path) and placing the file there by hand without chezmoi add to check if it works?

I suspect you have exact: true the .chezmoiexternal.toml, and that's causing the misbehavior. If it turns out to be, I think that it should be considered to automatically "ignore" the exact attribute for files which are specifically in the source state (i.e. make files in source state always have precedence over .chezmoiexternal defined files).

@felipecrs
Copy link
Contributor

felipecrs commented Nov 11, 2021

If it works by adding the file on the source state by hand, then the guilty here is the chezmoi add command. It was not supposed to add to the root of your source state, but to retain the correct hierarchy. Unless...

chezmoi add $ZSH_CUSTOM/plugins/bw --recursive

What is inside $ZSH_CUSTOM? Whatever is there, it needs to be prefixed with your home directory. So, if it's /home/user/whatever/folder then fine, but if it's anything else than that's why it didn't work properly.

@jaron-l
Copy link
Author

jaron-l commented Nov 11, 2021

My $ZSH_CUSTOM:

$ echo $ZSH_CUSTOM
/home/lund/.oh-my-zsh/custom

where the real path of _bw needs to be /home/lund/.oh-my-zsh/custom/plugins/bw/_bw

My .chezmoiexternal.toml file
[".oh-my-zsh"]
    type = "archive"
    url = "https://github.com/ohmyzsh/ohmyzsh/archive/master.tar.gz"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
[".oh-my-zsh/custom/plugins/zsh-syntax-highlighting"]
    type = "archive"
    url = "https://github.com/zsh-users/zsh-syntax-highlighting/archive/master.tar.gz"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
[".oh-my-zsh/custom/themes/powerlevel10k"]
    type = "archive"
    url = "https://github.com/romkatv/powerlevel10k/archive/master.tar.gz"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
[".oh-my-zsh/custom/plugins/zsh-autosuggestions"]
    type = "archive"
    url = "https://github.com/zsh-users/zsh-autosuggestions/archive/master.tar.gz"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"
[".oh-my-zsh/custom/plugins/zsh-completions"]
    type = "archive"
    url = "https://github.com/zsh-users/zsh-completions/archive/master.tar.gz"
    exact = true
    stripComponents = 1
    refreshPeriod = "168h"

I'm not sure how to make the correct file path structure for this file but here's me trying:
When adding dot_oh-my-zsh/custom/plugins/bw/executable_literal__bw.tmpl to my chezmoi repo, and running chezmoi diff, I get:

chezmoi: .oh-my-zsh: inconsistent state (dot_oh-my-zsh, https://github.com/ohmyzsh/ohmyzsh/archive/master.tar.gz); .oh-my-zsh/custom: inconsistent state (dot_oh-my-zsh/custom, https://github.com/ohmyzsh/ohmyzsh/archive/master.tar.gz); .oh-my-zsh/custom/plugins: inconsistent state (dot_oh-my-zsh/custom/plugins, https://github.com/ohmyzsh/ohmyzsh/archive/master.tar.gz)

@felipecrs
Copy link
Contributor

felipecrs commented Nov 11, 2021

Sorry, executable_ and neither literal_ are needed. I built a working example for you in my dotfiles, using deno. It's working fine for me and I plan to use it even more!

felipecrs/dotfiles@749a9e3

Would you mind taking a look on what I needed to do and try to replicate to see if it works? By the way, I had to run some autoload and compinit commands after doing it at least once because OMZ wasn't doing it for me despite it should.

If so, this should definitely become a guide in https://chezmoi.io, it's amazing how chezmoi can help us here!

However, to deal with the exact: true we will still need:

If it turns out to be, I think that it should be considered to automatically "ignore" the exact attribute for files which are specifically in the source state (i.e. make files in source state always have precedence over .chezmoiexternal defined files).

As otherwise it gives the error stated by @jaron-l at #1614 (comment). @twpayne WDYT?

And, @jaron-l, until a fix for this is in place, I suggest you disable exact: true for oh-my-zsh external as I did.

@twpayne
Copy link
Owner

twpayne commented Nov 11, 2021

The problem here is that the file gets added to chezmoi's repo at the base level, i.e. $(chezmoi source-path)/plugins/bw/_bw, which is not the correct position to be installed in for .oh-my-zsh to pick it up. Perhaps this is because .oh-my-zsh is in the .chezmoiexternal.toml?

Yes, this is #1574. Unfortunately, fixing it is quite tricky.

Neat trick with the completions file as a template using output. This should help with #660 as well.

@jaron-l
Copy link
Author

jaron-l commented Nov 11, 2021

@felipecrs Wow, you are amazing. It worked wonderfully! chezmoi is impressive! I didn't need to do the extra compinit or autoload so I'm not sure what happened there.

@felipecrs
Copy link
Contributor

I didn't need to do the extra compinit or autoload so I'm not sure what happened there.

It's probably because I used to use antigen before switching fully to chezmoiexternal and it left something behind. Despite OMZ should have taken care of it automatically (and that's why you didn't need to run it), something wrong happened. But I no longer have a reproducible environment, otherwise I would fill a bug for OMZ.

@twpayne twpayne added the support Support request label Nov 11, 2021
@felipecrs
Copy link
Contributor

felipecrs commented Nov 11, 2021

@twpayne I think this deserves a new guide in the docs, but it can't be done unless #1574 is finished because otherwise it would include a workaround (exact: false.

So I suggest we keep this issue open until the aforementioned guide is merged.

@dmikalova
Copy link

I've been using a run_completions.zsh that just runs all the completion commands and has them print out to a dir that zsh adds to fpath - fpath is like path but where zsh looks for completions:
completions script
setting fpath
DIR is set in the sourcing script, ie zshrc

Due to run_completions.sh being execed within chezmoi I was getting some kind of stdout error, so I couldn't just do cmd > output and instead had to use dd to write out the completions.

@terrymunro
Copy link

Sorry, executable_ and neither literal_ are needed. I built a working example for you in my dotfiles, using deno. It's working fine for me and I plan to use it even more!

felipecrs/dotfiles@749a9e3

Would you mind taking a look on what I needed to do and try to replicate to see if it works? By the way, I had to run some autoload and compinit commands after doing it at least once because OMZ wasn't doing it for me despite it should.

If so, this should definitely become a guide in https://chezmoi.io, it's amazing how chezmoi can help us here!

However, to deal with the exact: true we will still need:

If it turns out to be, I think that it should be considered to automatically "ignore" the exact attribute for files which are specifically in the source state (i.e. make files in source state always have precedence over .chezmoiexternal defined files).

As otherwise it gives the error stated by @jaron-l at #1614 (comment). @twpayne WDYT?

And, @jaron-l, until a fix for this is in place, I suggest you disable exact: true for oh-my-zsh external as I did.

FWIW this works for me with type = "archive" but does not seem to work with type = "git-repo" which gives an inconsistent state error. :(

@twpayne
Copy link
Owner

twpayne commented Mar 4, 2022

FWIW this works for me with type = "archive" but does not seem to work with type = "git-repo" which gives an inconsistent state error. :(

Correct, this is working as intended. git-repo externals are limited to running git init and git pull in a directory, which means that the directory contents are managed by git. If the directory contents are managed by git then they cannot be managed by chezmoi as otherwise there would be no single source of truth, which would lead to conflicts.

@terrymunro
Copy link

terrymunro commented Mar 4, 2022

Correct, this is working as intended. git-repo externals are limited to running git init and git pull in a directory, which means that the directory contents are managed by git. If the directory contents are managed by git then they cannot be managed by chezmoi as otherwise there would be no single source of truth, which would lead to conflicts.

Understandable and it's not a problem, given that there is a solution (using the archive method).

But surely you can agree it's not an unreasonable use-case, where the git repository has an ignored directory that they expect is modified by the user, so no conflict would have occurred.
For example:

  • Oh My Zsh ignores the custom directory
  • NVChad also ignores a custom directory

I doubt it's worth trying to parse the .gitignore just to support this safely, I just thought it should be worth mentioning in case someone googles their way here.

@twpayne
Copy link
Owner

twpayne commented Mar 9, 2022

But surely you can agree it's not an unreasonable use-case, where the git repository has an ignored directory that they expect is modified by the user, so no conflict would have occurred.

I agree that it's a reasonable use-case. At the same time, the expectation of what is modified by the user is not encoded in the .gitignore file.

I doubt it's worth trying to parse the .gitignore just to support this safely, I just thought it should be worth mentioning in case someone googles their way here.

I did investigate this in #1421 and #1623, including an attempted implementation in #1709, but the details turned out to be much more tricky than I anticipated. The workaround of using an archive is reasonable for now.

@twpayne
Copy link
Owner

twpayne commented May 23, 2022

I've added a note to #1574 to include @felipecrs's neat trick in the docs once #1574 is fixed. As the original issue is resolved, I'll close this issue now.

@twpayne twpayne closed this as completed May 23, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 31, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
support Support request
Projects
None yet
Development

No branches or pull requests

5 participants