Skip to content

feat(#1851): add bookmarks.persist, default path: vim.fn.stdpath("data") .. "/nvim-tree-bookmarks.json", disabled by default#3033

Merged
alex-courtis merged 18 commits intonvim-tree:masterfrom
xiantang:master
Jan 11, 2026
Merged

feat(#1851): add bookmarks.persist, default path: vim.fn.stdpath("data") .. "/nvim-tree-bookmarks.json", disabled by default#3033
alex-courtis merged 18 commits intonvim-tree:masterfrom
xiantang:master

Conversation

@xiantang
Copy link
Collaborator

@xiantang xiantang commented Dec 22, 2024

Copy link
Member

@alex-courtis alex-courtis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! I'll give it a full review and test in the next few days.

Initial thoughts:

  • Should we be using vim.json.encode instead of the fn ?
  • Please don't move existing methods (constructor, toggle)
  • This should be an optional feature in nvim-tree-opts, disabled by default
  • This needs checking and safety
    • Use a pcall or similar to prevent an error being raised
    • Report failures to the user

@HadyMash

This comment has been minimized.

@alex-courtis
Copy link
Member

any updates?

I'm happy with this providing the above is addressed.

@xiantang
Copy link
Collaborator Author

@alex-courtis updated

@alex-courtis alex-courtis changed the title WIP: Support Persist Bookmarks feat(#1851): persist bookmarks Feb 16, 2025
@alex-courtis
Copy link
Member

Proposed help, please correct indexes and run make help-update when done.

==============================================================================
 5.19 OPTS: BOOKMARKS                               *nvim-tree-opts-bookmarks*

*nvim-tree.bookmarks.persist*
Persist bookmarks to a json file containing a list of absolute paths.
Type: `boolean` | `string`, Default: `false`

`true`: use default: `stdpath("data") .. "/nvim-tree-bookmarks.json"`
`string`: absolute path of your choice.

Copy link
Member

@alex-courtis alex-courtis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking fantastic! It's very robust and works well.

Please

if explorer then
for _, node in pairs(explorer.marks:list()) do
status.bookmarks[node.absolute_path] = node.type
for key, node in pairs(explorer.marks.marks) do
Copy link
Member

@alex-courtis alex-courtis Feb 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is private and should not be accessed, see CI failure

Please use Marks:list()

I know this is not your code, but we can clean this up by using self.explorer (guaranteed not null) instead of calling core.

Edit: it appears that self.explorer.marks:list() is now returning an array of booleans instead of an array of nodes.

Comment on lines 514 to 517
marks = {
enable_persistence = false,
save_path = nil, -- nil will default to stdpath("data") .. "/nvim-tree-bookmarks.json"
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
marks = {
enable_persistence = false,
save_path = nil, -- nil will default to stdpath("data") .. "/nvim-tree-bookmarks.json"
},
bookmarks = {
persist = false,
},

Rather than a toggle and path, we can use just one option that is boolean or string. This is consistent with other options.

See proposed help

We then add the type explitictly so that it may be validated. Add to ACCEPTED_TYPES:

  bookmarks = {
    persist = { "boolean", "string" },
  },

@alex-courtis
Copy link
Member

I've added you to this repository so that you may push branches and run CI in the future.

@alex-courtis
Copy link
Member

Apologies, I was not clear about my request to simplify options and proposed help

Attached is a patch with those changes

gunzip simplify_options.diff.gz
git apply simplify_options.diff

simplify_options.diff.gz

@bburgess19
Copy link

bburgess19 commented May 16, 2025

@xiantang I was looking for this feature! Could you kindly add the patched changes so we can all benefit from your implementation?

Thank you and @alex-courtis for working on this :)

@alex-courtis
Copy link
Member

@xiantang I was looking for this feature! Could you kindly add the patched changes so we can all benefit from your implementation?

Thank you and @alex-courtis for working on this :)

If we don't hear back from @xiantang I would be most grateful for a new PR from you @bburgess19 with all the changes.

@alex-courtis
Copy link
Member

@xiantang

Would you like me to complete this and merge it?

@xiantang
Copy link
Collaborator Author

xiantang commented Jun 14, 2025 via email

@xiantang
Copy link
Collaborator Author

xiantang commented Jun 14, 2025 via email

@alex-courtis
Copy link
Member

sorry for misunderstanding, u can complete this merge request.

I would be very grateful if you completed. You deserve all the credit for this great feature.

@xiantang
Copy link
Collaborator Author

xiantang commented Jan 5, 2026

i will work on this feature.

Copilot AI review requested due to automatic review settings January 5, 2026 05:07

This comment was marked as spam.

Co-authored-by: Alexander Courtis <alex@courtis.org>
xiantang and others added 6 commits January 5, 2026 13:17
- Rename opts.marks to opts.bookmarks for better clarity
- Simplify persist option to boolean | string (true uses default path)
- Implement lazy node resolution for loaded bookmarks
- Update documentation with new bookmarks configuration
- Improve bulk operations to use public list() method consistently
- Rename opts.marks to opts.bookmarks for better clarity
- Simplify persist option to boolean | string (true uses default path)
- Implement lazy node resolution for loaded bookmarks
- Update documentation with new bookmarks configuration
- Improve bulk operations to use public list() method consistently
Co-authored-by: Alexander Courtis <alex@courtis.org>
@xiantang
Copy link
Collaborator Author

xiantang commented Jan 5, 2026

@alex-courtis i think its ready for review now

@xiantang xiantang requested a review from alex-courtis January 5, 2026 05:45
@alex-courtis
Copy link
Member

Many thanks for getting onto this one. I'll get to a review by this weekend.

Please, please don't create copilot reviews :)

@alex-courtis
Copy link
Member

I can't block the copilot user. I have tried to limit it at the org level.

I guess the next step is Add Copilot custom instructions

@xiantang
Copy link
Collaborator Author

xiantang commented Jan 5, 2026

Many thanks for getting onto this one. I'll get to a review by this weekend.

Please, please don't create copilot reviews :)

It's really annoying; I've already disabled it.

Copy link
Member

@alex-courtis alex-courtis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! A couple of small fixes and we're good to merge.

Test cases

1. Persist one mark then restart:

OK - mark is shown

2. Remove one mark then restart:

OK - mark not shown, file empty

3. Persist mark on file, quit, delete it, restart:

OK - mark is still in file

4. chmod 444 ~/.local/share/nvim/nvim-tree-bookmarks.json and mark:

FAIL - error shows "Invalid bookmarks.save_path" not "Invalid bookmarks.persist"

5. Repeat above and mark:

OK - no messages, persistence disabled

6. echo foobarbaz > ~/.local/share/nvim/nvim-tree-bookmarks.json:

OK - correct behaviour

message doesn't match the style of save failures, containing some stack: "Failed to load bookmarks: ...ker/start/nvim-tree.lua.dev/lua/nvim-tree/marks/init.lua:49: Expected value but found invalid token at character 1"

However there's not much we can do about that due to lua's poor exception handling. We'd need to check each and every io, file, vim.json call which is just not practical. It's fine: the save case will likely be the most common and has a nice message.

7. Reopen tree:

OK - no messages, persistence disabled for explorer instance

Error message will appear when you creat a new explorer instance however that seems like reasonable behaviour.

persist = "/tmp/foo.json"

OK - persists

persist = "/foo/bar/foo.json"

OK - error

Recommendations

  • 4: fix message

Small Fixes

  • Please use a string.format for all notify calls.

notify.warn("Failed to load bookmarks: " .. loaded_marks) string concatenation can throw an exception on nils

See https://github.com/xiantang/nvim-tree.lua/blob/3fc8de198c15ec4e5395f57b70579b3959976960/lua/nvim-tree/git/runner.lua#L219

  • Remove "Enabling this is not useful as there is no means yet to persist bookmarks" from help

This is now useful :)

@xiantang
Copy link
Collaborator Author

im fixing it

…ation

- Replace string concatenation with string.format in bookmark error messages
- Remove outdated comment about bookmark persistence from documentation
@xiantang
Copy link
Collaborator Author

d49cf10 @alex-courtis, please check this commit, if u have small changes to make, just apply them on this PR and merge it. tks

@xiantang xiantang requested a review from alex-courtis January 10, 2026 08:08
Copy link
Member

@alex-courtis alex-courtis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks for your contribution!

@alex-courtis alex-courtis changed the title feat(#1851): persist bookmarks feat(#1851): add bookmarks.persist, default path: vim.fn.stdpath("data") .. "/nvim-tree-bookmarks.json", disabled by default Jan 11, 2026
@alex-courtis alex-courtis merged commit c89215d into nvim-tree:master Jan 11, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Persist Bookmarks

5 participants