Skip to content

Commit cc5eda6

Browse files
committed
faet: async rename and create file
1 parent 3c4958a commit cc5eda6

File tree

9 files changed

+372
-50
lines changed

9 files changed

+372
-50
lines changed

doc/nvim-tree-lua.txt

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Requirements
6464
==============================================================================
6565
2. QUICK START *nvim-tree-quickstart*
6666

67-
Setup should be run in a lua file or in a |lua-heredoc| if using in a vim file.
67+
Setup should be run in a lua file or in a |lua-heredoc| if using in a vim file. >lua
6868

6969
-- examples for your init.lua
7070

@@ -169,7 +169,7 @@ setup() function takes one optional argument: configuration table. If omitted
169169
nvim-tree will be initialised with default configuration.
170170

171171
Subsequent calls to setup will replace the previous configuration.
172-
>
172+
>lua
173173
require("nvim-tree").setup { -- BEGIN_DEFAULT_OPTS
174174
auto_reload_on_write = true,
175175
disable_netrw = false,
@@ -394,6 +394,12 @@ Subsequent calls to setup will replace the previous configuration.
394394
watcher = false,
395395
},
396396
},
397+
experimental = {
398+
async = {
399+
create_file = false,
400+
rename_file = false,
401+
}
402+
}
397403
} -- END_DEFAULT_OPTS
398404
<
399405

@@ -405,7 +411,7 @@ Completely disable netrw
405411

406412
It is strongly advised to eagerly disable netrw, due to race conditions at vim
407413
startup.
408-
Set the following at the very beginning of your `init.lua` / `init.vim`: >
414+
Set the following at the very beginning of your `init.lua` / `init.vim`: >lua
409415
vim.g.loaded_netrw = 1
410416
vim.g.loaded_netrwPlugin = 1
411417
<
@@ -452,7 +458,7 @@ function.
452458
- `name`: `string`
453459
- `type`: `"directory"` | `"file"` | `"link"`
454460

455-
Example: sort by name length: >
461+
Example: sort by name length: >lua
456462
local sort_by = function(nodes)
457463
table.sort(nodes, function(a, b)
458464
return #a.name < #b.name
@@ -646,7 +652,7 @@ This can be used to attach keybindings to the tree buffer.
646652
When on_attach is "disabled", it will use the older mapping strategy, otherwise it
647653
will use the newer one.
648654
Type: `function(bufnr)`, Default: `"disable"`
649-
e.g. >
655+
e.g. >lua
650656
local api = require("nvim-tree.api")
651657

652658
local function on_attach(bufnr)
@@ -780,7 +786,7 @@ UI rendering setup
780786
Type: `string` or `function(root_cwd)`, Default: `":~:s?$?/..?"`
781787

782788
Function is passed the absolute path of the root folder and should return a string.
783-
e.g. >
789+
e.g. >lua
784790
my_root_folder_label = function(path)
785791
return ".../" .. vim.fn.fnamemodify(path, ":t")
786792
end
@@ -1012,7 +1018,7 @@ Configuration for various actions.
10121018
The function should return the window id that will open the node,
10131019
or `nil` if an invalid window is picked or user cancelled the action.
10141020
Type: `string` | `function`, Default: `"default"`
1015-
e.g. s1n7ax/nvim-window-picker plugin: >
1021+
e.g. s1n7ax/nvim-window-picker plugin: >lua
10161022
window_picker = {
10171023
enable = true,
10181024
picker = require('window-picker').pick_window,
@@ -1134,6 +1140,21 @@ Configuration for diagnostic logging.
11341140
|nvim-tree.filesystem_watchers| processing, verbose.
11351141
Type: `boolean`, Default: `false`
11361142

1143+
*nvim-tree.experimental*
1144+
Configuration for experimental features.
1145+
1146+
*nvim-tree.experimental.async*
1147+
Control experimental async behavior.
1148+
1149+
*nvim-tree.experimental.async.create_file*
1150+
Toggle async behavior of create file operation.
1151+
Type: `boolean`, Default: `false`
1152+
1153+
*nvim-tree.experimental.async.rename_file*
1154+
Toggle async behavior of rename file operation. Note this also
1155+
influence bulk move action.
1156+
Type: `boolean`, Default: `false`
1157+
11371158
==============================================================================
11381159
4.1 VINEGAR STYLE *nvim-tree-vinegar*
11391160

@@ -1144,8 +1165,8 @@ it in a specific way:
11441165

11451166
- Use `require"nvim-tree".open_replacing_current_buffer()` instead of the
11461167
default open command.
1147-
You can easily implement a toggle using this too:
1148-
>
1168+
You can easily implement a toggle using this too: >lua
1169+
11491170
local function toggle_replace()
11501171
local view = require"nvim-tree.view"
11511172
local api = require"nvim-tree.api"
@@ -1157,8 +1178,8 @@ You can easily implement a toggle using this too:
11571178
end
11581179
<
11591180
- Use the `edit_in_place` action to edit files. It's bound to `<C-e>` by
1160-
default, vinegar uses `<CR>`. You can override this with:
1161-
>
1181+
default, vinegar uses `<CR>`. You can override this with: >lua
1182+
11621183
require"nvim-tree".setup {
11631184
view = {
11641185
mappings = {
@@ -1179,8 +1200,8 @@ A good functionality to enable is |nvim-tree.hijack_directories|.
11791200
5. API *nvim-tree-api*
11801201

11811202
Nvim-tree's public API can be used to access features.
1182-
>
1183-
e.g. >
1203+
1204+
e.g. >lua
11841205
local api = require("nvim-tree.api")
11851206
api.tree.toggle()
11861207
<
@@ -1262,6 +1283,10 @@ exists.
12621283
- api.events: *nvim-tree.api.events*
12631284
- subscribe `(eventType: Event, callback: function(...args))`
12641285
- Event (enum type, please see |nvim_tree_events_kind|)
1286+
- subscribe_async `(eventType: Event, callback: function(...args))`
1287+
Same as `subscribe`, except the callback could be async. The async
1288+
callback will be called in the same context as the event. See also
1289+
*nvim-tree.api.async*.
12651290

12661291
- api.live_filter: *nvim-tree.api.live_filter*
12671292
- start
@@ -1277,6 +1302,10 @@ exists.
12771302
- navigate.prev
12781303
- navigate.select
12791304

1305+
- api.async: *nvim-tree.api.async*
1306+
- call `(func: function, ...args)`
1307+
- in_async
1308+
12801309
==============================================================================
12811310
6. MAPPINGS *nvim-tree-mappings*
12821311

@@ -1300,7 +1329,7 @@ Setting your own mapping in the configuration will soon be deprecated, see
13001329
Default `'n'`.
13011330

13021331
Examples:
1303-
>
1332+
>lua
13041333
local function print_node_path(node)
13051334
print(node.absolute_path)
13061335
end
@@ -1382,7 +1411,7 @@ DEFAULT MAPPINGS *nvim-tree-default-mappings
13821411
`m` toggle_mark Toggle node in bookmarks
13831412
`bmv` bulk_move Move all bookmarked nodes into specified location
13841413

1385-
>
1414+
>lua
13861415
view.mappings.list = { -- BEGIN_DEFAULT_MAPPINGS
13871416
{ key = { "<CR>", "o", "<2-LeftMouse>" }, action = "edit" },
13881417
{ key = "<C-e>", action = "edit_in_place" },
@@ -1444,7 +1473,7 @@ All the following highlight groups can be configured by hand. Aside from
14441473
groups.
14451474

14461475
Example (in your `init.vim`):
1447-
>
1476+
>vim
14481477
highlight NvimTreeSymlink guifg=blue gui=bold,underline
14491478
<
14501479
You should have 'termguicolors' enabled, otherwise, colors will not be
@@ -1534,7 +1563,7 @@ to |nvim_tree_registering_handlers| for more information.
15341563
Handlers are registered by calling |nvim-tree-api| `events.subscribe`
15351564
function with an `events.Event` kind.
15361565

1537-
e.g. handler for node renamed: >
1566+
e.g. handler for node renamed: >lua
15381567
local api = require("nvim-tree.api")
15391568
local Event = api.events.Event
15401569

@@ -1595,12 +1624,11 @@ To get the list of marked paths, you can call
15951624
Navigation for marks is not bound by default in nvim-tree because we don't
15961625
want to focus the tree view each time we wish to switch to another mark.
15971626

1598-
This requires binding bookmark navigation yourself.
1599-
1600-
-- in your lua configuration
1601-
vim.keymap.set("n", "<leader>mn", require("nvim-tree.api").marks.navigate.next)
1602-
vim.keymap.set("n", "<leader>mp", require("nvim-tree.api").marks.navigate.prev)
1603-
vim.keymap.set("n", "<leader>ms", require("nvim-tree.api").marks.navigate.select)
1627+
This requires binding bookmark navigation yourself. >lua
1628+
-- in your lua configuration
1629+
vim.keymap.set("n", "<leader>mn", require("nvim-tree.api").marks.navigate.next)
1630+
vim.keymap.set("n", "<leader>mp", require("nvim-tree.api").marks.navigate.prev)
1631+
vim.keymap.set("n", "<leader>ms", require("nvim-tree.api").marks.navigate.select)
16041632

16051633
==============================================================================
16061634
10. OS SPECIFIC RESTRICTIONS *nvim-tree-os-specific*

lua/nvim-tree.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,12 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS
702702
watcher = false,
703703
},
704704
},
705+
experimental = {
706+
async = {
707+
create_file = false,
708+
rename_file = false,
709+
},
710+
},
705711
} -- END_DEFAULT_OPTS
706712

707713
local function merge_options(conf)

lua/nvim-tree/actions/fs/create-file.lua

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,28 @@ local core = require "nvim-tree.core"
55
local notify = require "nvim-tree.notify"
66

77
local find_file = require("nvim-tree.actions.finders.find-file").fn
8+
local async = require "nvim-tree.async"
89

910
local M = {}
1011

12+
---@async
1113
local function create_and_notify(file)
12-
local ok, fd = pcall(vim.loop.fs_open, file, "w", 420)
13-
if not ok then
14+
local fd, err
15+
if M.enable_async then
16+
err, fd = async.call(vim.loop.fs_open, file, "w", 420)
17+
else
18+
fd, err = vim.loop.fs_open(file, "w", 420)
19+
end
20+
if err then
1421
notify.error("Couldn't create file " .. file)
1522
return
1623
end
17-
vim.loop.fs_close(fd)
24+
if M.enable_async then
25+
async.call(vim.loop.fs_close, fd)
26+
async.schedule()
27+
else
28+
vim.loop.fs_close(fd)
29+
end
1830
events._dispatch_file_created(file)
1931
end
2032

@@ -49,7 +61,62 @@ local function get_containing_folder(node)
4961
return node.absolute_path:sub(0, -node_name_size - 1)
5062
end
5163

52-
function M.fn(node)
64+
---@async
65+
local async_fn = async.wrap(function(node)
66+
local containing_folder = get_containing_folder(node)
67+
68+
local input_opts = { prompt = "Create file ", default = containing_folder, completion = "file" }
69+
70+
local new_file_path = async.call(vim.ui.input, input_opts)
71+
utils.clear_prompt()
72+
if not new_file_path or new_file_path == containing_folder then
73+
return
74+
end
75+
76+
if utils.file_exists(new_file_path) then
77+
notify.warn "Cannot create: file already exists"
78+
return
79+
end
80+
81+
-- create a folder for each path element if the folder does not exist
82+
-- if the answer ends with a /, create a file for the last path element
83+
local is_last_path_file = not new_file_path:match(utils.path_separator .. "$")
84+
local path_to_create = ""
85+
local idx = 0
86+
87+
local num_nodes = get_num_nodes(utils.path_split(utils.path_remove_trailing(new_file_path)))
88+
local is_error = false
89+
for path in utils.path_split(new_file_path) do
90+
idx = idx + 1
91+
local p = utils.path_remove_trailing(path)
92+
async.schedule()
93+
if #path_to_create == 0 and vim.fn.has "win32" == 1 then
94+
path_to_create = utils.path_join { p, path_to_create }
95+
else
96+
path_to_create = utils.path_join { path_to_create, p }
97+
end
98+
if is_last_path_file and idx == num_nodes then
99+
create_file(path_to_create)
100+
elseif not utils.file_exists(path_to_create) then
101+
local err = async.call(vim.loop.fs_mkdir, path_to_create, 493)
102+
if err then
103+
notify.error("Could not create folder " .. path_to_create .. " :" .. err)
104+
is_error = true
105+
break
106+
end
107+
async.schedule()
108+
events._dispatch_folder_created(new_file_path)
109+
end
110+
end
111+
if not is_error then
112+
notify.info(new_file_path .. " was properly created")
113+
end
114+
115+
-- synchronously refreshes as we can't wait for the watchers
116+
find_file(utils.path_remove_trailing(new_file_path))
117+
end, 1)
118+
119+
function M.fn(node, cb)
53120
node = node and lib.get_last_group_node(node)
54121
if not node or node.name == ".." then
55122
node = {
@@ -59,6 +126,10 @@ function M.fn(node)
59126
}
60127
end
61128

129+
if M.enable_async then
130+
return async_fn(node, cb)
131+
end
132+
62133
local containing_folder = get_containing_folder(node)
63134

64135
local input_opts = { prompt = "Create file ", default = containing_folder, completion = "file" }
@@ -113,6 +184,7 @@ end
113184

114185
function M.setup(opts)
115186
M.enable_reload = not opts.filesystem_watchers.enable
187+
M.enable_async = opts.experimental.async.create_file
116188
end
117189

118190
return M

0 commit comments

Comments
 (0)