feat: add {line_fragment} variable and forge-aware path mapping - #34
einsteinjava wants to merge 17 commits into
Conversation
Add a new 'ghpath' mapping (<leader>cp) that copies code with an
absolute path and GitHub-style line fragment on top:
/path/to/file.py#L5-L8
<code content>
New format variable {github_line} produces GitHub-style line fragments:
- Single line: L5
- Range: L5-L8
Also updates vimdoc to reflect current config options and adds
{github_line} to the documented format variables.
|
@einsteinjava Hi, thanks for the contribution! |
The 5 formatter_spec tests asserting get_variables() output were
missing the new {github_line} field, causing CI failures.
Added github_line = 'L<N>' (single line) or 'L<N>-L<M>' (range)
to each expected table to match the new return value.
|
@zhisme tests fixed — 142/142 passing now. The 5 formatter_spec assertions for |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
zhisme
left a comment
There was a problem hiding this comment.
One critical issue that should be rewritten.
formatter.lua
L5-L8 fragment is GitHub-specific convention, not generic. Proof from providers:
┌───────────────┬──────────────────────────────┐
│ provider │ range fragment │
├───────────────┼──────────────────────────────┤
│ github.lua │ #L5-L8 ← matches github_line │
├───────────────┼──────────────────────────────┤
│ gitlab.lua │ #L5-8 (no 2nd L) │
├───────────────┼──────────────────────────────┤
│ bitbucket.lua │ #lines-5:8 │
└───────────────┴──────────────────────────────┘
So github_line hardcodes GitHub's flavor into the provider-agnostic formatter.
Formatter vars are all generic (filepath, line, remote_url, copied_text) —
injecting one provider's dialect breaks that neutrality.
Also duplication: #L..-L.. logic now lives 2 places —
providers/github.lua:build_url (line 26-30) and formatter.lua. GitHub changes →
2 edits.
Proper fix:
- Add M.line_fragment(line_start, line_end) to providers/github.lua (pure, no git_info).
- build_url calls it → dedup.
- Formatter obtains fragment via provider, not inline. Formatter currently
has zero provider context.
- Add M.line_fragment() to github, gitlab, bitbucket providers
- Refactor build_url() in each provider to call line_fragment() (dedup)
- Add url_builder.get_line_fragment() with GitHub-style fallback
- Wire line_fragment through formatter.get_variables() as optional param
- Rename {github_line} -> {line_fragment} everywhere (config, validation,
tests, README, vimdoc)
- Update ghpath docs to describe auto-detected fragment per provider
|
Thank you for the review @zhisme. I have refactored the PR to address your feedback. Changes madeThree-phase refactor applied (verified locally, 142/142 tests passing): Phase 1 — Provider owns line fragmentEach provider now has a standalone
Phase 2 — Wire through url_builder → formatter → main
Phase 3 — Rename variableRenamed How it works nowVerificationAll 142 existing tests pass, 0 failures, 0 errors. No architectural cross-boundary was crossed — the formatter stays pure and receives the pre-computed fragment. Adding a new provider (e.g. SourceHut) only requires implementing |
- Fix stylua formatting in main.lua (line break for long line) - Add 6 tests for url_builder.get_line_fragment() covering: - fallback when no git info (single + range) - provider-specific fragment - missing line_fragment method on provider - nil provider fallback
zhisme
left a comment
There was a problem hiding this comment.
I think I get your idea now, and we can modify default behavior actually. but you'll need to update docs accordingly and update current tests line_url_fragment for all available providers. that's good change. once we finish with formatting and architecture I will merge that. good PR, thanks!
|
also lets rename pr title to general solution not just ghpath that we have discussed |
|
Renamed PR title as requested — now |
|
@einsteinjava you have missed my comments regarding gh path/documentations and questions. Please check them, so I can proceed with review, thanks |
|
@zhisme You're right, I missed a few things — let me address them: 1. Mapping name The mapping and internal name are still GitHub-specific but the feature is now forge-agnostic. I'll rename the mapping to 2. Docs updates I stripped some instructional text from vimdoc when adding the ghpath section — specifically the "Plugin copies line under cursor into your unnamed register. Paste somewhere" lines. That was unintentional cleanup during the rebase. I'll restore those for the existing mappings and only omit the obvious for the new section. Also, the version bump 1.0→2.0 — that might be presumptuous. Happy to revert to 1.1 or whatever you prefer. 3. Tests You mentioned testing line_url_fragment for all available providers in your last review. I added url_builder_spec.lua tests covering the get_line_fragment function (with git, without git, provider missing line_fragment, nil provider) but I didn't add explicit unit tests for each provider's line_fragment() method itself. I'll add those. I'll push a cleanup commit addressing all of the above. Let me know if you'd like the mapping named something else. |
…ider line_fragment tests
- Bump vimdoc version to 3.1
- Restore old visual-selection examples alongside new pathmap examples
- Remove pathmap from default config (mapping + output_format), docs-only
- Rename {line_fragment} -> {line_url_fragment} for clarity
- Add explanatory comment to codecov.yml
|
Addressed all review feedback:
All 158 tests pass, 0 failures. Ready for re-review @zhisme. |
zhisme
left a comment
There was a problem hiding this comment.
Well done, few latest comments to fix and we are ready to merge 👍
zhisme
left a comment
There was a problem hiding this comment.
@einsteinjava check my 2 last points and we are good to go
- Remove codecov.yml per maintainer request (not an intended change)
- Make {line_url_fragment} the default format instead of {line}
- Remove pathmap mapping — forge-aware fragments work out of the box
- Update README and vimdoc: remove pathmap section, update all examples
- Tests: 158/158 pass, lint clean, fmt clean
Closes zhisme#32. get_git_info() now caches results by absolute file path, eliminating 4 subprocess calls on every subsequent copy from the same file. Cache is invalidated on DirChanged via autocmd registered in setup(). - git.lua: add git_info_cache table + invalidate_cache() - main.lua: register DirChanged autocmd to clear cache - tests: 3 new cache behavior tests (hit, invalidate, per-file) - 161/161 tests pass, lint clean
|
@einsteinjava could you check why CI is red? It warns about low coverage, I think that's why you did changes to codecov.yml. Lets not modify any codecov configs, but add missing specs for that exact lines. New code needs new tests check this URL |
|
@einsteinjava lets fix those leftovers and we are ready to merge 🤝 |
zhisme
left a comment
There was a problem hiding this comment.
@einsteinjava thanks for the feature. good to go! 🎉
I will test a few days before merging upstream
Keeping '# {filepath}:{line}' as the default avoids silently changing output
for existing users and avoids the git shell-outs get_line_fragment triggers
on every copy.
Fragment was 'L4-L6', so '{filepath}:{line_url_fragment}' produced the invalid
'foo.rb:L4-L6'. Fragments now include the separator: '#L4-L6' on GitHub,
'#L4-6' on GitLab, '#lines-4:6' on Bitbucket, plain ':4-6' with no remote.
Formats use '{filepath}{line_url_fragment}'.
The variable carries its own ':' or '#', so '{filepath}:{line_url_fragment}'
would render as 'foo.rb:#L4-L6'. Fail at setup instead of at copy time.
Also wrap the PR's new vimdoc lines to 78 columns and fix the contents alignment.
What
Adds a new
{github_line}format variable and aghpathmapping (<leader>cp) that copies code with an absolute path and GitHub-style line fragment on top.Output format
Single line:
Visual selection:
New format variable
{github_line}produces GitHub-style line fragments:L5L5-L8Files changed
formatter.lua— addsgithub_lineto the variables tablemain.lua—ghpathmapping uses absolute pathsuser_config_validation.lua— allows{github_line}in format stringsconfig.lua— addsghpathas a default mapping withoutput_formatsREADME.md— documents the new variable and mappingdoc/copy_with_context.txt— updates vimdoc (was outdated)Use case
This format is ideal for sharing code in GitHub issues, PRs, or pasting into AI assistants where the absolute path + line number gives precise context without needing a remote URL.