Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/doc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ jobs:
run: nvim --headless --clean -c "helptags doc/" -c qa
- uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "doc: auto generate"
commit_message: "docs: auto generate"
branch: ${{ github.head_ref }}
file_pattern: doc
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ tag:
echo | tee -a $$MSG_FILE; \
git log --pretty=format:%s --invert-grep --grep doc:* $(LATEST_TAG)..HEAD | tee -a $$MSG_FILE; \
echo; \
echo git tag -a $(TAG) -F $$MSG_FILE; \
git tag -a $(TAG) -F $$MSG_FILE; \
else \
echo "Missing TAG definition."; \
fi
Expand Down
71 changes: 64 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ shallow clones automatically. It aims to provide a similar experience to
- [Supported URLs](#supported-urls)
- [Examples](#examples)
- [Limitations](#limitations)
- [:desktop_computer: XDG Handling](#desktop_computer-xdg-handling)
- [:notebook: Recipes](#notebook-recipes)
- [:grey_question: Interactive Opening](#grey_question-interactive-opening)
- [:evergreen_tree: nvim-tree](#evergreen_tree-nvim-tree)
Expand All @@ -66,7 +67,7 @@ shallow clones automatically. It aims to provide a similar experience to
- [:pencil: Customizing Default URL](#pencil-customizing-default-url)
- [:house_with_garden: Private Repositories - Parse HTTP as SSH](#house_with_garden-private-repositories---parse-http-as-ssh)
- [:toothbrush: Close & Clean](#toothbrush-close--clean)
- [:crystal_ball: Future Plans / Thoughts](#crystal_ball-future-plans--thoughts)
- [:footprints: Tridactyl - Open in Neovim](#footprints-tridactyl---open-in-neovim)
- [:scroll: License](#scroll-license)
<!-- panvimdoc-ignore-end -->

Expand All @@ -77,6 +78,7 @@ shallow clones automatically. It aims to provide a similar experience to
- Ephemeral repositories - cleanup when Neovim exits.
- Telescope extension to revisit previously opened repositories.
- Close buffers or clean opened repositories in current session.
- XDG handling.

<!-- panvimdoc-ignore-start -->

Expand Down Expand Up @@ -287,7 +289,7 @@ M.config = {
-- Delay window closing.
close_after_ms = 3000,
-- Window mode.
-- Options: floating|split
---@type "floating"|"split"
mode = "floating",
-- Window configuration for floating mode.
-- See `:h nvim_open_win`.
Expand Down Expand Up @@ -330,6 +332,20 @@ M.config = {
---@type "always"|"never"|"current"
delete_repo_dir = "current",
},
-- XDG handling of `nvim-getdev` URIs.
-- Requires: `xdg-mime` and `xdg-open`.
xdg_handler = {
enabled = false,
-- A location for the desktop entry.
desktop_entry_path = vim.fs.normalize(
vim.fn.stdpath "data" .. "/../applications/git-dev.desktop"
),
-- Launcher script.
script = {
path = vim.fn.expand "~/.local/bin/git-dev-open",
content = '#!/usr/bin/env sh\nnvim -c GitDevXDGHandle\\ "$@"',
},
},
-- More verbosity.
verbose = false,
}
Expand Down Expand Up @@ -423,6 +439,38 @@ knowledge of the repository. To workaround it, the parser module invokes a Git
command to list all references and looks for the longest match. The remainder
will be selected as the file path.

## :desktop_computer: XDG Handling
To enable XDG handling, adjust your config:
```lua
{
...
xdg_handler = {
enabled = true,
},
}
```
The next plugin setup will generate a desktop entry for `git-dev.nvim`,
a launcher script that will be called by the desktop entry (to workaround
limitations of escaping with `xdg-open`) and will it as the default handler for
`nvim-gitdev` URIs.

`git-dev.nvim` URIs follow the following scheme:
```
nvim-gitdev://<method>/?param1=value1&param2=value2
```
Example:
```
nvim-gitdev://open/?repo=moyiz/git-dev.nvim
```
Parameter names are ignored. All parameter values are unpacked and passed to the
method as positional arguments.

> [!NOTE]
> The desktop entry contains `Terminal=true` attribute, which could or could not
> work depends on your setup. If a new terminal is not launched, update
> `opts.xdg_handler.script.content` and wrap the command with a terminal.
> Example: `content = '#!/usr/bin/env sh\nalacritty -e nvim -c GitDevXDGHandle\\ "$@"'`


## :notebook: Recipes
### :grey_question: Interactive Opening
Expand Down Expand Up @@ -573,7 +621,7 @@ Then, the parser trims the "domain" and proceeds as usual. Output:
```

### :toothbrush: Close & Clean
Keymap example to close / clean current active repository.
Keymap example to close / clean currently active repository.
```lua
{
"moyiz/git-dev.nvim",
Expand All @@ -597,14 +645,23 @@ Keymap example to close / clean current active repository.
},
}
}

```

### :footprints: Tridactyl - Open in Neovim
Requires [native messenger](https://github.com/tridactyl/tridactyl?tab=readme-ov-file#extra-features-through-native-messaging).

<!-- panvimdoc-ignore-start -->
```vim
bind ;go composite get_current_url | shellescape | js -p tri.excmds.exclaim("alacritty -e nvim -c \'GitDevOpen " + JS_ARG + "\'")
```
Or if you enabled `xdg_handler`:
```vim
bind ;go composite get_current_url | shellescape | js -p tri.excmds.exclaim("xdg-open nvim-gitdev://open/?repo=" + JS_ARG)
```

## :crystal_ball: Future Plans / Thoughts
- Open repository in visual selection / current "word".
- Persisting repositories.
Set the keymap and terminal by preference.

<!-- panvimdoc-ignore-start -->

## :scroll: License
See [License](./LICENSE).
Expand Down
29 changes: 4 additions & 25 deletions lua/git-dev/gitcmd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,10 @@ end
---Spawns a command and returns its handle and std{out,err} pipes.
---@param cmd string
function GitCmd:_spawn(cmd, callback)
local stdout = uv.new_pipe()
local stderr = uv.new_pipe()

local handle
handle = uv.spawn(
"sh",
{ args = { "-c", cmd }, stdio = { nil, stdout, stderr } },
function(code)
if callback then
callback(code)
end
if handle then
handle:close()
end
stdout:read_stop()
stdout:close()
stderr:read_stop()
stderr:close()
end
)

uv.read_start(stdout, self.on_output)
uv.read_start(stderr, self.on_output)

return { handle = handle, stdout = stdout, stderr = stderr }
local s = require("git-dev.utils").sh_spawn(cmd, callback)
uv.read_start(s.stdout, self.on_output)
uv.read_start(s.stderr, self.on_output)
return s
end

---@class CloneOpts
Expand Down
30 changes: 29 additions & 1 deletion lua/git-dev/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ M.config = {
-- Delay window closing.
close_after_ms = 3000,
-- Window mode.
-- Options: floating|split
---@type "floating"|"split"
mode = "floating",
-- Window configuration for floating mode.
-- See `:h nvim_open_win`.
Expand Down Expand Up @@ -99,6 +99,20 @@ M.config = {
---@type "always"|"never"|"current"
delete_repo_dir = "current",
},
-- XDG handling of `nvim-getdev` URIs.
-- Requires: `xdg-mime` and `xdg-open`.
xdg_handler = {
enabled = false,
-- A location for the desktop entry.
desktop_entry_path = vim.fs.normalize(
vim.fn.stdpath "data" .. "/../applications/git-dev.desktop"
),
-- Launcher script.
script = {
path = vim.fn.expand "~/.local/bin/git-dev-open",
content = '#!/usr/bin/env sh\nnvim -c GitDevXDGHandle\\ "$@"',
},
},
-- More verbosity.
verbose = false,
}
Expand Down Expand Up @@ -477,6 +491,20 @@ M.setup = function(opts)
---@type GitDevSession
M.session = require("git-dev.session"):init()

local xdg = require "git-dev.xdg"
if M.config.xdg_handler.enabled then
xdg.enable(M.config.xdg_handler)
vim.api.nvim_create_user_command("GitDevXDGHandle", function(cmd_args)
local uri = U.parse_cmd_args(cmd_args)
M.ui:print(xdg.handle(uri))
end, {
desc = "xdg-open handler for git-dev.nvim URIs.",
nargs = "*",
})
else
xdg.disable(M.config.xdg_handler)
end

-- Create commands
vim.api.nvim_create_user_command("GitDevOpen", function(cmd_args)
local repo, ref, cmd_opts = U.parse_cmd_args(cmd_args)
Expand Down
4 changes: 2 additions & 2 deletions lua/git-dev/store.lua
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ end

function Store._write(path, data, callback)
uv.fs_open(path, "w", o600, function(err1, fd)
if err1 then
if err1 or not fd then
log_err("Error opening " .. path .. ": " .. err1)
return
end
Expand Down Expand Up @@ -123,7 +123,7 @@ function Store:load()
return
end
local fd, err = uv.fs_open(self.path, "r", o600)
if err then
if err or not fd then
log_err(err)
return
end
Expand Down
83 changes: 73 additions & 10 deletions lua/git-dev/utils.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
-- A module for de-cluttering other modules.
local U = {}
local uv = vim.uv

---Safe `nvim_buf_get_var`.
---@param buf_id? number
Expand All @@ -13,20 +14,21 @@ function U.buf_get_var(buf_id, name)
return value
end

function U.load_param(o)
local ok, res = pcall(function()
return load("return " .. o)()
end)
if ok and res ~= nil then
return res
end
return o
end

---Parses and unpacks command arguments.
function U.parse_cmd_args(cmd_args)
local load_param = function(o)
local ok, res = pcall(function()
return load("return " .. o)()
end)
if ok and res ~= nil then
return res
end
return o
end
local parsed = {}
for _, arg in pairs(cmd_args.fargs) do
table.insert(parsed, load_param(arg))
table.insert(parsed, U.load_param(arg))
end
return unpack(parsed)
end
Expand Down Expand Up @@ -85,4 +87,65 @@ function U.map(f, arr)
return results
end

function U.sh_spawn(cmd, callback)
local stdout = uv.new_pipe()
local stderr = uv.new_pipe()

local handle
handle = uv.spawn(
"sh",
{ args = { "-c", cmd }, stdio = { nil, stdout, stderr } },
function(code)
if callback then
callback(code)
end
if handle then
handle:close()
end
stdout:read_stop()
stdout:close()
stderr:read_stop()
stderr:close()
end
)

return { handle = handle, stdout = stdout, stderr = stderr }
end

U.o600 = 384
U.o700 = 448

function U.overwrite_if_changed(path, expected_content, perms)
perms = perms or U.o600
local current_content
local stat = uv.fs_stat(path)
if stat then
local fd, err = uv.fs_open(path, "r", perms)
if err or not fd then
vim.api.nvim_err_writeln(err or "Failed to open")
return
end
current_content = uv.fs_read(fd, stat.size)
uv.fs_close(fd)
end
if current_content ~= expected_content then
vim.fn.mkdir(vim.fs.dirname(path), "p")
uv.fs_open(path, "w", perms, function(err1, fd)
if err1 or not fd then
vim.api.nvim_err_writeln(err1 or "Failed to open")
return
end
uv.fs_write(fd, expected_content, nil, function(err2, _)
if err2 then
vim.api.nvim_err_writeln(err2 or "Failed to write")
end
uv.fs_close(fd, function(err3)
if err3 then
vim.api.nvim_err_writeln(err3 or "Failed to close")
end
end)
end)
end)
end
end
return U
Loading