├── .gitignore ├── doc ├── .gitignore └── askpass.txt ├── denops └── askpass │ ├── const.ts │ ├── cli.ts │ └── main.ts ├── plugin └── askpass.vim ├── deno.jsonc ├── .gitmessage ├── Makefile ├── LICENSE ├── .github └── workflows │ ├── udd.yml │ └── test.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /.deno 2 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | -------------------------------------------------------------------------------- /denops/askpass/const.ts: -------------------------------------------------------------------------------- 1 | export const ASKPASS_ADDRESS = "ASKPASS_ADDRESS"; 2 | -------------------------------------------------------------------------------- /plugin/askpass.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_askpass') 2 | finish 3 | endif 4 | let g:loaded_askpass = 1 5 | -------------------------------------------------------------------------------- /deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "lint": { 3 | "files": { 4 | "exclude": [".deno"] 5 | } 6 | }, 7 | "fmt": { 8 | "files": { 9 | "exclude": [".deno"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.gitmessage: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Guide (v1.0) 4 | # 5 | # 👍 :+1: Apply changes. 6 | # 7 | # 🌿 :herb: Add or update things for tests. 8 | # ☕ :coffee: Add or update things for developments. 9 | # 📦 :package: Add or update dependencies. 10 | # 📝 :memo: Add or update documentations. 11 | # 12 | # 🐛 :bug: Bugfixes. 13 | # 💋 :kiss: Critical hotfixes. 14 | # 🚿 :shower: Remove features, codes, or files. 15 | # 16 | # 🚀 :rocket: Improve performance. 17 | # 💪 :muscle: Refactor codes. 18 | # 💥 :boom: Breaking changes. 19 | # 💩 :poop: Bad codes needs to be improved. 20 | # 21 | # How to use: 22 | # git config commit.template .gitmessage 23 | # 24 | # Reference: 25 | # https://github.com/lambdalisue/emojiprefix 26 | -------------------------------------------------------------------------------- /denops/askpass/cli.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S deno run --no-check --allow-env=ASKPASS_ADDRESS --allow-net=127.0.0.1 2 | import { Session } from "https://deno.land/x/msgpack_rpc@v3.1.4/mod.ts"; 3 | import { writeAll } from "https://deno.land/std@0.128.0/io/mod.ts"; 4 | import { ASKPASS_ADDRESS } from "./const.ts"; 5 | 6 | const addr = Deno.env.get(ASKPASS_ADDRESS); 7 | if (!addr) { 8 | throw new Error(`No ${ASKPASS_ADDRESS} environment variable found`); 9 | } 10 | 11 | const conn = await Deno.connect(JSON.parse(addr)); 12 | const session = new Session(conn, conn); 13 | const input = await session.call("ask", Deno.args[0] ?? "") as string; 14 | const encoder = new TextEncoder(); 15 | await writeAll(Deno.stdout, encoder.encode(input)); 16 | session.close(); 17 | conn.close(); 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGETS := $$(find . \( -name '*.ts' -or -name '*.md' \) -not -path './.deno/*') 2 | 3 | .DEFAULT_GOAL := help 4 | 5 | help: 6 | @cat $(MAKEFILE_LIST) | \ 7 | perl -ne 'print if /^\w+.*##/;' | \ 8 | perl -pe 's/(.*):.*##\s*/sprintf("%-20s",$$1)/eg;' 9 | 10 | fmt: FORCE ## Format code 11 | @deno fmt --config deno.jsonc 12 | 13 | fmt-check: FORCE ## Format check 14 | @deno fmt --check --config deno.jsonc 15 | 16 | lint: FORCE ## Lint code 17 | @deno lint --config deno.jsonc 18 | 19 | type-check: FORCE ## Type check 20 | @deno test --unstable --no-run ${TARGETS} 21 | 22 | test: FORCE ## Test 23 | @deno test --unstable -A --no-check --jobs 24 | 25 | deps: FORCE ## Update dependencies 26 | @deno run -A https://deno.land/x/udd@0.7.2/main.ts ${TARGETS} 27 | @make fmt 28 | 29 | FORCE: 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Alisue, hashnote.net 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /doc/askpass.txt: -------------------------------------------------------------------------------- 1 | *askpass.txt* Use Vim/Neovim prompt for CLI user inputs 2 | 3 | Author: Alisue 4 | License: MIT license 5 | 6 | ============================================================================= 7 | CONTENTS *askpass-contents* 8 | 9 | INTRODUCTION |askpass-introduction| 10 | INTERFACE |askpass-interface| 11 | VARIABLE |askpass-variable| 12 | 13 | 14 | ============================================================================= 15 | INTRODUCTION *askpass-introduction* 16 | 17 | Askpass ( *askpass.vim* ) is a plugin that open a prompt on Vim/Neovim when 18 | some program (e.g. SSH) ask user input (e.g Key file passphrase) through a job 19 | on Vim/Neovim. 20 | 21 | 22 | ============================================================================= 23 | INTERFACE *askpass-interface* 24 | 25 | ----------------------------------------------------------------------------- 26 | VARIABLE *askpass-variable* 27 | 28 | *g:askpass#disable_ssh* 29 | Do NOT overwrite "DISPLAY" and "SSH_ASKPASS" environment variables. 30 | 31 | Default: 0 32 | 33 | *g:askpass#disable_sudo* 34 | Do NOT overwrite "SUDO_ASKPASS" environment variable. 35 | 36 | Default: 0 37 | 38 | 39 | ============================================================================= 40 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 41 | -------------------------------------------------------------------------------- /.github/workflows/udd.yml: -------------------------------------------------------------------------------- 1 | name: udd 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | 7 | jobs: 8 | udd: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: denoland/setup-deno@v1 13 | with: 14 | deno-version: "1.x" 15 | - name: Update dependencies 16 | run: | 17 | make deps > ../output.txt 18 | env: 19 | NO_COLOR: 1 20 | - name: Read ../output.txt 21 | id: log 22 | uses: juliangruber/read-file-action@v1 23 | with: 24 | path: ../output.txt 25 | - name: Commit changes 26 | run: | 27 | git config user.name '${{ github.actor }}' 28 | git config user.email '${{ github.actor }}@users.noreply.github.com' 29 | git commit -a -F- < 16 | 17 |
18 | With lambdalisue/gin.vim 19 |

20 | 21 | ## Requirements 22 | 23 | - [denops.vim](https://github.com/vim-denops/denops.vim) 24 | 25 | ## Similar projects 26 | 27 | - [lambdalisue/guise.vim](https://github.com/lambdalisue/guise.vim) 28 | 29 | ## License 30 | 31 | The code in this repository follows MIT license, texted in [LICENSE](./LICENSE). 32 | Contributors need to agree that any modifications sent in this repository follow 33 | the license. 34 | -------------------------------------------------------------------------------- /denops/askpass/main.ts: -------------------------------------------------------------------------------- 1 | import type { Denops } from "https://deno.land/x/denops_std@v3.1.4/mod.ts"; 2 | import * as path from "https://deno.land/std@0.128.0/path/mod.ts"; 3 | import * as batch from "https://deno.land/x/denops_std@v3.1.4/batch/mod.ts"; 4 | import * as vars from "https://deno.land/x/denops_std@v3.1.4/variable/mod.ts"; 5 | import * as fn from "https://deno.land/x/denops_std@v3.1.4/function/mod.ts"; 6 | import * as unknownutil from "https://deno.land/x/unknownutil@v2.0.0/mod.ts"; 7 | import { Session } from "https://deno.land/x/msgpack_rpc@v3.1.4/mod.ts"; 8 | import { ASKPASS_ADDRESS } from "./const.ts"; 9 | 10 | export async function main(denops: Denops): Promise { 11 | const [disableSsh, disableSudo] = await batch.gather( 12 | denops, 13 | async (denops) => { 14 | await vars.g.get(denops, "askpass_disable_ssh", 0); 15 | await vars.g.get(denops, "askpass_disable_sudo", 0); 16 | }, 17 | ) as [number, number]; 18 | listen(denops).catch((e) => { 19 | console.error( 20 | `[askpass] Unexpected error occurred for Neovim listener: ${e}`, 21 | ); 22 | }); 23 | const askpass = path.fromFileUrl(new URL("./cli.ts", import.meta.url)); 24 | const display = await vars.e.get(denops, "DISPLAY", "dummy:0"); 25 | await batch.batch(denops, async (denops) => { 26 | await vars.e.set(denops, "ASKPASS", askpass); 27 | if (!disableSsh) { 28 | // NOTE: it may be necessary to redirect the input from /dev/null 29 | // https://man.openbsd.org/ssh#SSH_ASKPASS 30 | await vars.e.set( 31 | denops, 32 | "DISPLAY", 33 | display, 34 | ); 35 | await vars.e.set(denops, "SSH_ASKPASS", askpass); 36 | } 37 | if (!disableSudo) { 38 | // NOTE: Add `-A` option to enable this feature 39 | // https://man7.org/linux/man-pages/man8/sudo.8.html 40 | await vars.e.set(denops, "SUDO_ASKPASS", askpass); 41 | } 42 | }); 43 | } 44 | 45 | async function listen(denops: Denops): Promise { 46 | const listener = Deno.listen({ 47 | hostname: "127.0.0.1", 48 | port: 0, // Automatically select free port 49 | }); 50 | await vars.e.set( 51 | denops, 52 | ASKPASS_ADDRESS, 53 | JSON.stringify(listener.addr), 54 | ); 55 | for await (const conn of listener) { 56 | handle(denops, conn).catch((e) => { 57 | console.error(`[askpass] Unexpected error occurred: ${e}`); 58 | }); 59 | } 60 | } 61 | 62 | function handle(denops: Denops, conn: Deno.Conn): Promise { 63 | const session = new Session(conn, conn, { 64 | async ask(prompt: unknown) { 65 | unknownutil.assertString(prompt); 66 | return await fn.inputsecret(denops, prompt); 67 | }, 68 | }); 69 | return session.waitClosed(); 70 | } 71 | --------------------------------------------------------------------------------