Skip to content

action to rename the base name of file without changing directory or extension (#1155) #1791

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Dec 16, 2022

Conversation

ianhomer
Copy link
Collaborator

@ianhomer ianhomer commented Nov 30, 2022

fixes #1155

Experimental solution for #1155

Not sure whether this should be bound to key by default. Would like to add to documentation somewhere, although other actions such as full_rename are only mentioned in docs via the default key mapping.

The relative_rename action can be bound in custom config with

  view = {
    mappings = {
      list = {
       { key = "r", action = "rename_relative" },
      },
    },
  },

edited : changed action name

@ianhomer ianhomer changed the title relative rename action (#1155) action to rename the base name of file without changing directory or extension (#1155) Nov 30, 2022
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.

Works beautifully. I will enjoy using this feature.

You will be the owner of this feature, responsible for resolving any immediate issues that arise.

@alex-courtis
Copy link
Member

@sarmong your testing of this feature would be gratefully appreciated.

@alex-courtis
Copy link
Member

Tested OK:

  • API
  • mapping

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.

I'm thinking again about the name relative_rename, which isn't quite a full explanation and base name isn't quite right.

Looking at vimlike naming for inspiration it maps to fnamemodify(bufname, ":t:r"). That's "tail root". We have two changes going on here. The root is arguably the most significant.

If we were building from scratch today I imagine something like this:
r rename ":t" - using tail is different, but arguably better UX
e rename_root ":t:r"
<c-r> rename_full ":p"

Thinking about fnamemodify now makes me realise that we could use that instead of manually calculating the name. Apologies, I should have realised this earlier.

Proposal

  • change rename_relative to rename_root - Alex
  • use fnamemodify in rename-file.lua.fn - Ian

Maybe later

Change rename to use the tail; this is a break of existing functionality and needs further thought. Raised #1803

@ianhomer
Copy link
Collaborator Author

ianhomer commented Dec 4, 2022

Thx for the feedback, I'm traveling for the next few days, but will action this when I get back. No urgency to get it in, would prefer to get it right than rush it in.

@sarmong
Copy link
Collaborator

sarmong commented Dec 4, 2022

Hey, thanks for making this feature!

  1. Found a bug - if you have directory with dots in its name then it will trim out part after the last dot.
  2. Imho, rename_root is also a bit confusing, because root oftentimes refers to the root directory of the project. I found that in most programing languages file name without extension is called either stem or basename. I've never heard or used stem in this context, but it is a shorter word, whereas basename is much more common and understandable.

Copy link
Collaborator

@gegoune gegoune left a comment

Choose a reason for hiding this comment

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

Thanks for doing it.

Once again we are adding specialised functions rather than providing building blocks.

Imagine having a function that receives path for buffer under cursor - whatever is returned will be a candidate for renaming.

Input: path as /my/awesome.file.c, returning: path:gsub('awesome', ''), would set. /my/|.file.c as a rename candidate (| is cursor position).

We could then easily provide some builtins built on that, and adding more would be as simple as that:

action = actions.rename(path) return vim.fn.fnamemodify(path, ':t') end,

We could also make it accept fnamemodify's modifier like so:

action = action.rename(':t'),

Function would allow users greater flexibility -like returning precomputed candidates.

full_rename could then be refactored to just return the same path for backwards compatibility.

Are you willing to go this direction, @ianhomer? What do you think @alex-courtis? I think this would go a long way.

@@ -1328,6 +1328,7 @@ DEFAULT MAPPINGS *nvim-tree-default-mappings
`D` trash trash a file via |trash| option
`r` rename rename a file
`<C-r>` full_rename rename a file and omit the filename on input
`e` rename_root rename a file with filename-modifiers ':t:r' without changing extension
Copy link
Collaborator

@gegoune gegoune Dec 4, 2022

Choose a reason for hiding this comment

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

Since we already have full_rename let's follow up with rename_basename.
That is obviously if we don't gp 'function|string' route as described above.

@ianhomer
Copy link
Collaborator Author

ianhomer commented Dec 4, 2022

I've done a minor change to use fnamemodify instead of custom string searching ... however I've not gone as far a few of the other suggestions here.

Regarding the /my/|.file.c suggestion, for me I don't find that behaviour as convenient as just seeing the basename stem, since my primary use case for renaming a file is a slight tweak of the current name, perhaps correcting a spelling mistake. If the original name has gone from the default value in the input box, then my rename is now harder. I also found the full absolute path in the input box a mild annoyance since I had more I could change than I wanted to. Perhaps that's another optional configuration - some people may prefer one vs the other.

I do like the generic function suggestion, and using vim fnamemodify modifiers. Not sure if there is a convenient vim function to rename a part of a filename based on the modifiers provided, but it wouldn't be hard to write that logic if needs be.

I'll be offline for the next few days, but happy to pick up any loose ends towards the end of the week if needs be.

@ianhomer
Copy link
Collaborator Author

ianhomer commented Dec 4, 2022

2. I've never heard or used stem in this context, but it is a shorter word, whereas basename is much more common and understandable.

"stem" is the unambiguous term for this (in C/Python world at least) - agree that it's not commonly known and in that sense perhaps not great semantics, "basename" normally includes the extension. Having read that stackoverflow post I'd personally vote for "stem" since it's short, sweet and well defined in C and Python.

@gegoune
Copy link
Collaborator

gegoune commented Dec 4, 2022

Regarding the /my/|.file.c suggestion, for me I don't find that behaviour as convenient as just seeing the basename, since my primary use case for renaming a file is a slight tweak of the current name, perhaps correcting a spelling mistake. If the original name has gone from the default value in the input box, then my rename is now harder. I also found the full absolute path in the input box a mild annoyance since I had more I could change than I wanted to. Perhaps that's another optional configuration - some people may prefer one vs the other.

That was just an example how new functionality could be used.

Your explanation of intentions and expectations only solidifies my earlier assumptions - there are so many use cases that there is no way nvim-tree can satisfy them all. Therefore providing an easy framework in form of actions.rename() seems like a way to go.

Rename API now supports filename modifiers as arguments, although
only with limited support of options. The function signature however
will allow improvements going forward. The API signature is backward
compatible, although the behviour has changed as per the next comment.

This change changes the default behaviour of the renames, rename_full is
what rename was, rename now just renames the tail (i.e. the filename)
@ianhomer
Copy link
Collaborator Author

ianhomer commented Dec 9, 2022

I've updated so that we have a rename API that takes arguments. Only argument it currently supports are the filename modifiers ":p", ":t" and ":t:r". Couldn't see a way to generically support all modifiers, however getting the API contract to where we want is key. Now this first argument is the file modifier, not the path to replace. I wonder if it needs to be a table argument so it could support different options.

I couldn't work out how to place the cursor in the vim.ui.input. Perhaps we could just count back the number of characters and programatically move the cursor (although I'm not sure which command I would use to do that in the vim.ui.input window). That feels like another feature, however now we're heading down a generic api for rename, this could be one of the opts.

Is this heading in the right direction?

edit: I've hopefully made this change is a way that is backward compatible from a API invocation point of view, however the behaviour of "full_rename" and "rename" actions have changed to renaming ":p" and ":t" as suggested above. Users will see this difference and for some it might not be desirable. I wonder if we need to support the previous "full_rename" behaviour with another action with users could configure in their mapping if they wished.

@alex-courtis
Copy link
Member

Hey, thanks for making this feature!

  1. Found a bug - if you have directory with dots in its name then it will trim out part after the last dot.
  2. Imho, rename_root is also a bit confusing, because root oftentimes refers to the root directory of the project. I found that in most programing languages file name without extension is called either stem or basename. I've never heard or used stem in this context, but it is a shorter word, whereas basename is much more common and understandable.

Thank you @sarmong

@alex-courtis
Copy link
Member

alex-courtis commented Dec 10, 2022

I've updated so that we have a rename API that takes arguments. Only argument it currently supports are the filename modifiers ":p", ":t" and ":t:r". Couldn't see a way to generically support all modifiers, however getting the API contract to where we want is key. Now this first argument is the file modifier, not the path to replace.

This works now and can be customised via action_cb:

          { 
            key = "<C-P>",
            action = "tr",
            action_cb = function()
              require("nvim-tree.actions.fs.rename-file").fn()(":t")
            end
          },

We just need to add API...

Edit: done:

          { 
            key = "<C-P>",
            action = "pr",
            action_cb = function(node)
              require("nvim-tree.api").fs.rename_node(node, ":t")
            end
          },

It will be a lot more usable when we get to on_attach #1579

@alex-courtis
Copy link
Member

Users will see this difference and for some it might not be desirable. I wonder if we need to support the previous "full_rename" behaviour with another action with users could configure in their mapping if they wished.

I'm happy; I was being to cautious. It's a break, but a reasonable one. #1803

@alex-courtis
Copy link
Member

alex-courtis commented Dec 10, 2022

Summary (please correct me):

Done:

  • rename basename
  • rename full path -> filename
  • rename modifiers
  • API

Outstanding:

  • input dialogue hacking etc.

It seems that we can merge this then deal with outstanding. Continuing discussion in #1803

@gegoune are you happy with the above and the addition of rename_basename as a default action and API?

return function(node)
function M.fn(initialisation_arg)
local default_modifier = ":t"
-- backwards compatibility, support modifier as boolean
Copy link
Member

Choose a reason for hiding this comment

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

This isn't API; we can break it.

Copy link
Member

Choose a reason for hiding this comment

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

Pushed a fix.

@@ -1196,8 +1196,10 @@ exists.
- create
- remove
- trash
- rename_node `(node: table, modifier?: string vim.fn.fnamemodify argument)`
Copy link
Member

Choose a reason for hiding this comment

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

I took the liberty of adding this new pattern. Will be improved later: #1753

function M.fn(default_modifier)
default_modifier = default_modifier or ":t"

return function(node, modifier)
Copy link
Member

Choose a reason for hiding this comment

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

I removed capability for the first argument to be a modifier after adding the API, as I couldn't see a use case.

I may be missing something...

@alex-courtis alex-courtis requested a review from gegoune December 10, 2022 03:14
@alex-courtis
Copy link
Member

You work here is greatly appreciated @ianhomer

This raised all sorts of good things well outside of the scope of your change. Thank you for pushing this one all this way.

rename ":t" and ":t:r" was moving file to root of project and not
maintaining sub-directory
which was loosing sub-directory on rename
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.

Tested OK: r, e, <c-r> custom:

  • file with no dot
  • file with many dots
  • rename remove / add trailing dot

e (file.) -> file. fails to rename, however that is quite reasonable as it is not clear what should happen.

Thanks for resolving the bugs I introduced @ianhomer

@alex-courtis alex-courtis merged commit 949913f into nvim-tree:master Dec 16, 2022
@Vinni-Cedraz

This comment was marked as off-topic.

@gegoune

This comment was marked as off-topic.

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.

Rename before extension
5 participants