-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Gin does what guise.vim and askpass.vim does so that users don't need to install guise.vim nor askpass.vim It uses `GIT_EDITOR` and `GIT_ASKPASS` enviroment variables
- Loading branch information
1 parent
94af015
commit b434dbc
Showing
8 changed files
with
278 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#!/usr/bin/env -S deno run --no-check --allow-env=GIN_PROXY_ADDRESS --allow-net=127.0.0.1 | ||
import { streams } from "../../deps.ts"; | ||
|
||
const resultPattern = /^([^:]+):(.*)$/; | ||
|
||
const addr = JSON.parse(Deno.env.get("GIN_PROXY_ADDRESS") ?? "null"); | ||
if (!addr) { | ||
throw new Error("GIN_PROXY_ADDRESS environment variable is required"); | ||
} | ||
|
||
const prompt = Deno.args[0]; | ||
if (!prompt) { | ||
throw new Error("No prompt is specified to the askpass"); | ||
} | ||
|
||
const encoder = new TextEncoder(); | ||
const decoder = new TextDecoder(); | ||
|
||
const conn = await Deno.connect(addr); | ||
await streams.writeAll(conn, encoder.encode(`askpass:${prompt}`)); | ||
await conn.closeWrite(); | ||
const result = decoder.decode(await streams.readAll(conn)); | ||
conn.close(); | ||
|
||
const m = result.match(resultPattern); | ||
if (!m) { | ||
throw new Error(`Unexpected result '${result}' is received`); | ||
} | ||
|
||
const [status, value] = m.slice(1); | ||
switch (status) { | ||
case "ok": | ||
console.log(value); | ||
Deno.exit(0); | ||
/* fall through */ | ||
case "err": | ||
console.error(value); | ||
Deno.exit(1); | ||
/* fall through */ | ||
default: | ||
throw new Error(`Unexpected status '${status}' is received`); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#!/usr/bin/env -S deno run --no-check --allow-env=GIN_PROXY_ADDRESS --allow-net=127.0.0.1 | ||
import { streams } from "../../deps.ts"; | ||
|
||
const resultPattern = /^([^:]+):(.*)$/; | ||
|
||
const addr = JSON.parse(Deno.env.get("GIN_PROXY_ADDRESS") ?? "null"); | ||
if (!addr) { | ||
throw new Error("GIN_PROXY_ADDRESS environment variable is required"); | ||
} | ||
|
||
const filename = Deno.args[0]; | ||
if (!filename) { | ||
throw new Error("No filename is specified to the editor"); | ||
} | ||
|
||
const encoder = new TextEncoder(); | ||
const decoder = new TextDecoder(); | ||
|
||
const conn = await Deno.connect(addr); | ||
await streams.writeAll(conn, encoder.encode(`editor:${filename}`)); | ||
await conn.closeWrite(); | ||
const result = decoder.decode(await streams.readAll(conn)); | ||
conn.close(); | ||
|
||
const m = result.match(resultPattern); | ||
if (!m) { | ||
throw new Error(`Unexpected result '${result}' is received`); | ||
} | ||
|
||
const [status, value] = m.slice(1); | ||
switch (status) { | ||
case "ok": | ||
Deno.exit(0); | ||
/* fall through */ | ||
case "err": | ||
console.error(value); | ||
Deno.exit(1); | ||
/* fall through */ | ||
default: | ||
throw new Error(`Unexpected status '${status}' is received`); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { Denops } from "../../deps.ts"; | ||
import { listen } from "./server.ts"; | ||
|
||
export function main(denops: Denops): void { | ||
listen(denops).catch((e) => | ||
console.error(`Unexpected error occured in the proxy server: ${e}`) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import { | ||
anonymous, | ||
autocmd, | ||
batch, | ||
deferred, | ||
Denops, | ||
fn, | ||
option, | ||
path, | ||
streams, | ||
unknownutil, | ||
vars, | ||
} from "../../deps.ts"; | ||
import { decodeUtf8, encodeUtf8 } from "../../util/text.ts"; | ||
import * as buffer from "../../util/buffer.ts"; | ||
|
||
const recordPattern = /^([^:]+?):(.*)$/; | ||
|
||
export async function listen(denops: Denops): Promise<void> { | ||
const listener = Deno.listen({ | ||
hostname: "127.0.0.1", | ||
port: 0, | ||
}); | ||
const [disableAskpass, disableEditor] = await batch.gather( | ||
denops, | ||
async (denops) => { | ||
await vars.g.get(denops, "gin_proxy_disable_askpass"); | ||
await vars.g.get(denops, "gin_proxy_disable_editor"); | ||
}, | ||
); | ||
await batch.batch(denops, async (denops) => { | ||
await vars.e.set( | ||
denops, | ||
"GIN_PROXY_ADDRESS", | ||
JSON.stringify(listener.addr), | ||
); | ||
if (!unknownutil.ensureBoolean(disableAskpass ?? false)) { | ||
await vars.e.set( | ||
denops, | ||
"GIT_ASKPASS", | ||
path.fromFileUrl(new URL("askpass.ts", import.meta.url)), | ||
); | ||
} | ||
if (!unknownutil.ensureBoolean(disableEditor ?? false)) { | ||
await vars.e.set( | ||
denops, | ||
"GIT_EDITOR", | ||
path.fromFileUrl(new URL("editor.ts", import.meta.url)), | ||
); | ||
} | ||
}); | ||
for await (const conn of listener) { | ||
handleConnection(denops, conn).catch((e) => console.error(e)); | ||
} | ||
} | ||
|
||
async function handleConnection( | ||
denops: Denops, | ||
conn: Deno.Conn, | ||
): Promise<void> { | ||
const record = decodeUtf8(await streams.readAll(conn)); | ||
const m = record.match(recordPattern); | ||
if (!m) { | ||
throw new Error(`Unexpected record '${record}' received`); | ||
} | ||
const [name, value] = m.slice(1); | ||
try { | ||
switch (name) { | ||
case "askpass": | ||
await handleAskpass(denops, conn, value); | ||
break; | ||
case "editor": | ||
await handleEditor(denops, conn, value); | ||
break; | ||
default: | ||
throw new Error(`Unexpected record prefix '${name}' received`); | ||
} | ||
} finally { | ||
conn.close(); | ||
} | ||
} | ||
|
||
async function handleAskpass( | ||
denops: Denops, | ||
conn: Deno.Conn, | ||
prompt: string, | ||
): Promise<void> { | ||
try { | ||
const value = await fn.inputsecret(denops, prompt); | ||
await streams.writeAll(conn, encodeUtf8(`ok:${value}`)); | ||
} catch (e: unknown) { | ||
await streams.writeAll(conn, encodeUtf8(`err:${e}`)); | ||
} | ||
} | ||
|
||
async function handleEditor( | ||
denops: Denops, | ||
conn: Deno.Conn, | ||
filename: string, | ||
): Promise<void> { | ||
try { | ||
await edit(denops, filename); | ||
await streams.writeAll(conn, encodeUtf8("ok:")); | ||
} catch (e: unknown) { | ||
await streams.writeAll(conn, encodeUtf8(`err:${e}`)); | ||
} | ||
} | ||
|
||
async function edit( | ||
denops: Denops, | ||
filename: string, | ||
): Promise<void> { | ||
await denops.cmd("silent noswapfile tab drop `=filename` | edit", { | ||
filename, | ||
}); | ||
const [winid, bufnr] = await batch.gather(denops, async (denops) => { | ||
await fn.win_getid(denops); | ||
await fn.bufnr(denops); | ||
}); | ||
unknownutil.assertNumber(winid); | ||
unknownutil.assertNumber(bufnr); | ||
const auname = `gin_editor_${winid}_${bufnr}`; | ||
const waiter = deferred<void>(); | ||
const [waiterId] = anonymous.once(denops, async () => { | ||
await autocmd.group(denops, auname, (helper) => { | ||
helper.remove(); | ||
}); | ||
waiter.resolve(); | ||
}); | ||
await buffer.ensure(denops, bufnr, async () => { | ||
await batch.batch(denops, async (denops) => { | ||
await option.bufhidden.setLocal(denops, "wipe"); | ||
await autocmd.group(denops, auname, (helper) => { | ||
helper.remove(); | ||
helper.define( | ||
["BufWipeout", "VimLeave"], | ||
"*", | ||
`call denops#request('gin', '${waiterId}', [])`, | ||
{ | ||
once: true, | ||
}, | ||
); | ||
}); | ||
}); | ||
}); | ||
await waiter; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters