├── .gitignore
├── LICENSE
├── README.md
├── dev
└── init.lua
├── doc
└── presentation.md
└── lua
├── nvim-docker.lua
└── nvim-docker
├── container-keymaps.lua
├── container-layout.lua
├── container-logs.lua
├── containers.lua
├── docker.lua
├── popup-keymaps.lua
└── tree-utils.lua
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Lua sources
2 | luac.out
3 |
4 | # luarocks build files
5 | *.src.rock
6 | *.zip
7 | *.tar.gz
8 |
9 | # Object files
10 | *.o
11 | *.os
12 | *.ko
13 | *.obj
14 | *.elf
15 |
16 | # Precompiled Headers
17 | *.gch
18 | *.pch
19 |
20 | # Libraries
21 | *.lib
22 | *.a
23 | *.la
24 | *.lo
25 | *.def
26 | *.exp
27 |
28 | # Shared objects (inc. Windows DLLs)
29 | *.dll
30 | *.so
31 | *.so.*
32 | *.dylib
33 |
34 | # Executables
35 | *.exe
36 | *.out
37 | *.app
38 | *.i*86
39 | *.x86_64
40 | *.hex
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 s1n7ax
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nvim-docker
2 |
3 | Docker management right inside Neovim!
4 |
5 | ## Features
6 |
7 |
8 | 
9 |
10 |
11 | - Container management
12 | - View containers on your local machine with live reloading
13 | - Bring containers up/down
14 | - Remove and rebuild containers
15 | - Send commands to containers (SoonTM)
16 | - View container logs
17 | - Configurable (SoonTM)
18 | - Docker compose integration (SoonTM)
19 | - Image management
20 | - View images on you local machine with live reloading (SoonTM)
21 | - Create new containers from images (SoonTM)
22 |
23 | ## Installation
24 |
25 | ### Packer
26 |
27 | ```lua
28 | use {
29 | 'dgrbrady/nvim-docker',
30 | requires = {'nvim-lua/plenary.nvim', 'MunifTanjim/nui.nvim'},
31 | rocks = '4O4/reactivex' -- ReactiveX Lua implementation
32 | }
33 | ```
34 |
35 | ## How to use
36 |
37 | In your lua config:
38 |
39 | ```lua
40 | local nvim_docker = require('nvim-docker')
41 | -- list containers
42 | nvim_docker.containers.list_containers()
43 |
44 | -- OR
45 | -- setting up keybindings since the `list_containers` fn does not have a default binding
46 | vim.keymap.set('n', 'C', nvim_docker.containers.list_containers)
47 | ```
48 |
49 | ### Default Keymaps
50 |
51 | | Binding | Where | Effect |
52 | | ------- | ----- | ------ |
53 | | `j` | Top popup | Move cursor down on container list |
54 | | `k` | Top popup | Move cursor up on container list |
55 | | `l` | Top popup | Expand container details |
56 | | `L` | Top popup | Expand all containers |
57 | | `h` | Top popup | Collapse container details |
58 | | `H` | Top popup | Collapse all containers |
59 | | `r` | Top popup | Restart container |
60 | | `dd` | Top popup | Deletes container (asks for confirmation) |
61 | | `t` | Top popup | View container logs |
62 | | `` | Top popup | Focus bottom popup |
63 | | `t` | Bottom popup | Toggles whether the cursor should be stuck to the bottom of the popup. Helpful if you want to watch the latest logs as they come in |
64 | | `` | Bottom popup | Focus top popup |
65 |
66 |
67 | ## Roadmap
68 |
69 | - [ ] Interact with containers
70 | - [x] Start container [12c8e6](https://github.com/dgrbrady/nvim-docker/commit/12c8e625a7f3864f89e11f0d24297a5ce1f09542)
71 | - [x] Stop container [12c8e6](https://github.com/dgrbrady/nvim-docker/commit/12c8e625a7f3864f89e11f0d24297a5ce1f09542)
72 | - [x] Restart container [39a1be](https://github.com/dgrbrady/nvim-docker/commit/39a1be419e7b6817bd9dd5474c1a2dd80790934b)
73 | - [x] Delete container [98b561](https://github.com/dgrbrady/nvim-docker/commit/98b5611fd81aca130f13d2bd319fa49a7a2f8ee5)
74 | - [x] View logs from container [c71005](https://github.com/dgrbrady/nvim-docker/commit/c71005aba5cc70fea33338cdcb50620e4fe2de8f)
75 | - [ ] Run command in container
76 | - [ ] Interact with images
77 | - [ ] List image
78 | - [ ] Delete image
79 | - [ ] Create container from image
80 | - [ ] Docker compose integration
81 | - [ ] Provide options for user configuration
82 | - [ ] Documentation
83 | - [ ] Telescope integration?
84 |
85 | ## Development
86 |
87 | * clone the project `git clone https://github.com/dgrbrady/nvim-docker`
88 | * go to the project folder `cd nvim-docker`
89 | * start editing `nvim --cmd "set rtp+=."`
90 | * reference the dev configurations `:luafile dev/init.lua`
91 | * run the `containers.list_containers()` function using `,w` keybind
92 |
--------------------------------------------------------------------------------
/dev/init.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | -- plugin name will be used to reload the loaded modules
3 | --]]
4 | local package_name = 'nvim-docker'
5 |
6 | -- add the escape character to special characters
7 | local escape_pattern = function (text)
8 | return text:gsub("([^%w])", "%%%1")
9 | end
10 |
11 | -- unload loaded modules by the matching text
12 | local unload_packages = function ()
13 | local esc_package_name = escape_pattern(package_name)
14 |
15 | for module_name, _ in pairs(package.loaded) do
16 | if string.find(module_name, esc_package_name) then
17 | package.loaded[module_name] = nil
18 | end
19 | end
20 | end
21 |
22 | -- executes the run method in the package
23 | local run_action = function ()
24 | require(package_name).containers.list_containers()
25 | end
26 |
27 | -- unload and run the function from the package
28 | function Reload_and_run()
29 | unload_packages()
30 | run_action()
31 | end
32 |
33 | local set_keymap = vim.api.nvim_set_keymap
34 |
35 | set_keymap('n', ',r', 'luafile dev/init.lua', {})
36 | set_keymap('n', ',w', 'lua Reload_and_run()', {})
37 |
--------------------------------------------------------------------------------
/doc/presentation.md:
--------------------------------------------------------------------------------
1 | # Neovim-Lua Plugin Development Beginner's Guide
2 |
3 | ## Before we start
4 |
5 | * Neovim Lua boilerplate: https://github.com/s1n7ax/neovim-lua-plugin-boilerplate
6 | * Neovim Lua video tutorials: https://youtube.com/playlist?list=PL0EgBggsoPCk1WCos2txThsxhg0fT5nqD
7 | * My Neovim configuration: https://github.com/s1n7ax/dotnvim
8 | * Terminal manager: https://github.com/s1n7ax/nvim-terminal
9 |
10 | ## Prerequisites
11 |
12 | * Neovim 0.5 or higher version
13 | * Git
14 | * GitHub Account
15 |
16 | ## Setting up the project
17 |
18 | * Create GitHub project
19 | * Clone the project
20 |
21 | ```bash
22 | git clone
23 | ```
24 |
25 | * Open Neovim for editing
26 |
27 | ```
28 | # NOTE: make sure to add current directory to runtime path
29 | # otherwise, Neovim does not know how to find your plugin
30 | nvim --cmd "set rtp+=."
31 | ```
32 |
33 | * Create Lua module in Lua source directory
34 |
35 | ```bash
36 | mkdir -p lua/greetings
37 | ```
38 |
39 | * Create init file and sub modules for the module
40 |
41 | ```bash
42 | touch lua/greetings/init.lua
43 | touch lua/greetings/awesome-module.lua
44 | ```
45 |
46 | ## Create greetings plugin
47 |
48 | * Add greet function to `awesome-module.lua`
49 |
50 | ```lua
51 | local function greet()
52 | print('testing')
53 | end
54 |
55 | return greet
56 | ```
57 |
58 | * Expose public APIs of the plugin
59 |
60 | ```lua
61 | local greet = require('greetings.awesome-module')
62 |
63 | return {
64 | greet = greet
65 | }
66 | ```
67 |
68 | * Testing plugin APIs
69 |
70 | ```vim
71 | # you should run this in the vim command line
72 | :lua require('greetings').greet()
73 | ```
74 |
75 | ## Few tips when developing plugins
76 |
77 | ### See changes without re opening Neovim
78 |
79 | Lua will not reload module if it already exists. The changes you made will be
80 | applied the next time you open the editor. But you can force Lua to reload the
81 | module for development.
82 |
83 | * Create `dev/init.lua` file
84 |
85 | ```bash
86 | mkdir -p dev
87 | touch dev/init.lua
88 | ```
89 |
90 | * Add following to `dev/init.lua` to force reloading
91 |
92 | ```
93 | -- force lua to import the modules again
94 | package.loaded['dev'] = nil
95 | package.loaded['greetings'] = nil
96 | package.loaded['greetings.awesome-module'] = nil
97 |
98 | -- [ , + r ] keymap to reload the lua file
99 | -- NOTE: someone need to source this file to apply these configurations. So, the
100 | -- very first time you open the project, you have to source this file using
101 | -- ":luafile dev/init.lua". From that point onward, you can hit the keybind to
102 | -- reload
103 | vim.api.nvim_set_keymap('n', ',r', 'luafile dev/init.lua', {})
104 | ```
105 |
106 | * While we are in the file, lets add shortcut to run the greeting plugin
107 |
108 | ```lua
109 | -- keybind to test the plugin
110 | Greetings = require('greetings')
111 | vim.api.nvim_set_keymap('n', ',w', 'lua Greetings.greet()', {})
112 | ```
113 |
114 |
115 | ## Learn more about Neovim-Lua
116 |
117 | * I release a video on YouTube once a year XD. [This is the link to playlist.](https://youtube.com/playlist?list=PL0EgBggsoPCk1WCos2txThsxhg0fT5nqD) You can subscribe to the channel too ;)
118 | * [nvim-lua-guide](https://github.com/nanotee/nvim-lua-guide) is awesome place
119 | to start learning Neovim-Lua APIs
120 | * Run `:h api` in Neovim to get all available Neovim-Lua APIs
121 | * Run `:h function` to learn about vim functions. You can run vim functions
122 | using `vim.fn.()`
123 | * Use [Neovim subreddit](https://www.reddit.com/r/neovim) to stay updated and ask questions
124 |
--------------------------------------------------------------------------------
/lua/nvim-docker.lua:
--------------------------------------------------------------------------------
1 | local containers = require('nvim-docker.containers')
2 |
3 | return {
4 | containers = containers,
5 | }
6 |
--------------------------------------------------------------------------------
/lua/nvim-docker/container-keymaps.lua:
--------------------------------------------------------------------------------
1 | local event = require('nui.utils.autocmd').event
2 | local docker = require('nvim-docker.docker')
3 | local container_logs = require('nvim-docker.container-logs')
4 |
5 | local _M = {}
6 |
7 | -- starts the container associated with the current tree node
8 | local function start_container(params)
9 | local node, _ = params.tree:get_node()
10 | if node ~= nil and node.container ~= nil then
11 | vim.notify('Starting container: ' .. node.container.name)
12 | docker({'container', 'start', node.container.id}):start()
13 | end
14 | end
15 |
16 | -- stops the container associated with the current tree node
17 | local function stop_container(params)
18 | local node, _ = params.tree:get_node()
19 | if node ~= nil and node.container ~= nil then
20 | vim.notify('Stopping container: ' .. node.container.name)
21 | docker({'container', 'stop', node.container.id}):start()
22 | end
23 | end
24 |
25 | -- restarts the container associated with the current tree node
26 | local function restart_container(params)
27 | local node, _ = params.tree:get_node()
28 | if node ~= nil and node.container ~= nil then
29 | vim.notify('Restarting container: ' .. node.container.name)
30 | docker({'container', 'restart', node.container.id}):start()
31 | end
32 | end
33 |
34 | -- deletes the container associated with the current tree node
35 | local function delete_container(params)
36 | local node, _ = params.tree:get_node()
37 | if node ~= nil and node.container ~= nil then
38 | vim.ui.select({'Yes', 'No'},{
39 | prompt = 'Delete ' .. node.container.name .. '[y/n]?',
40 | }, function (choice)
41 | if choice == 'Yes' then
42 | vim.notify('Deleting container: ' .. node.container.name)
43 | docker({'container', 'rm', node.container.id}):start()
44 | end
45 | end)
46 | end
47 | end
48 |
49 | -- view logs of the container associated with the current tree node
50 | local function view_logs(params)
51 | local node, _ = params.tree:get_node()
52 | if node ~= nil and node.container ~= nil then
53 | local layout = params.layout
54 | local log_popup = layout.log_popup
55 | local log_bufnr = log_popup.bufnr
56 | log_popup.border:set_text('top', node.container.name .. ' Logs', 'center')
57 | local line_count = vim.api.nvim_buf_line_count(log_bufnr)
58 | vim.api.nvim_buf_set_lines(log_bufnr, 0, line_count, false, {})
59 | local cursor_follow_logs = false
60 |
61 |
62 | local function toggle_cursor_follow_logs()
63 | cursor_follow_logs = not cursor_follow_logs
64 | if cursor_follow_logs == true then
65 | log_popup.border:set_text('bottom', '[stuck to bottom]', 'center')
66 | else
67 | log_popup.border:set_text('bottom', '')
68 | end
69 | end
70 |
71 | local function focus_logs()
72 | layout.main_popup:off(event.BufLeave)
73 | vim.api.nvim_set_current_win(layout.log_popup.winid)
74 | layout:_setup_main_popup_on_bufleave()
75 | vim.keymap.set('n', 't', toggle_cursor_follow_logs, {buffer = log_bufnr})
76 | end
77 |
78 | local function focus_main()
79 | cursor_follow_logs = false
80 | vim.api.nvim_set_current_win(layout.main_popup.winid)
81 | layout:_setup_main_popup_on_bufleave()
82 | vim.keymap.del('n', 't', {buffer=log_bufnr})
83 | end
84 |
85 |
86 | vim.keymap.set('n', '', focus_logs, {buffer = layout.main_popup.bufnr})
87 |
88 | vim.keymap.set('n', '', focus_main, {buffer = log_bufnr})
89 |
90 | focus_logs()
91 |
92 | container_logs.follow_logs(node.container.name, function (logs)
93 | if log_popup.bufnr ~= nil then
94 | for index, log in ipairs(logs) do
95 | vim.api.nvim_buf_set_lines(log_popup.bufnr, index, index + 1, false, {log})
96 | end
97 | vim.schedule(function ()
98 | if cursor_follow_logs == true then
99 | vim.api.nvim_win_set_cursor(log_popup.winid, {
100 | vim.api.nvim_buf_line_count(log_bufnr),
101 | 0
102 | })
103 | end
104 | end)
105 | end
106 | end)
107 | end
108 | end
109 |
110 | _M.extra_keymaps = {
111 | {'n', 'u', start_container, 'Start the highlighted container'},
112 | {'n', 'd', stop_container, 'Stop the highlighted container'},
113 | {'n', 'r', restart_container, 'Restart the highlighted container'},
114 | {'n', 'dd', delete_container, 'Delete the highlighted container'},
115 | {'n', 't', view_logs, 'View container logs'},
116 | }
117 |
118 | return _M
119 |
--------------------------------------------------------------------------------
/lua/nvim-docker/container-layout.lua:
--------------------------------------------------------------------------------
1 | local Layout = require('nui.layout')
2 | local Tree = require('nui.tree')
3 | local Popup = require('nui.popup')
4 | local event = require('nui.utils.autocmd').event
5 | local rx = require('reactivex')
6 |
7 | local popup_keymaps = require('nvim-docker.popup-keymaps')
8 | local tree_utils = require('nvim-docker.tree-utils')
9 | local ContainerLayout = Layout:extend('ContainerLayout')
10 | local docker = require('nvim-docker.docker')
11 |
12 | ---Component used to for managing containers
13 | ---@param layout_options table https://github.com/MunifTanjim/nui.nvim/tree/main/lua/nui/layout#options
14 | function ContainerLayout:init(layout_options, keymaps)
15 | self.mounted = false
16 | self.keymaps = keymaps
17 | self._containers = rx.Subject.create()
18 | local options = vim.tbl_deep_extend('force', layout_options or {}, {
19 | position = '50%',
20 | relative = 'editor',
21 | size = {
22 | height = '70%',
23 | width = '50%'
24 | }
25 | })
26 |
27 | self:_create_main_popup()
28 | self:_create_log_popup()
29 | ContainerLayout.super.init(self, options, Layout.Box({
30 | Layout.Box(self.main_popup, {size='50%'}),
31 | Layout.Box(self.log_popup, {size='50%'}),
32 | }, {dir = 'col'}))
33 | end
34 |
35 | function ContainerLayout:_setup_main_popup_on_bufleave()
36 | self.main_popup:on(event.BufLeave, function()
37 | local container_logs = require('nvim-docker.container-logs')
38 | container_logs.teardown()
39 | self.main_popup:unmount()
40 | local function close_timer()
41 | self.main_popup_timer:close()
42 | end
43 | pcall(close_timer)
44 | self:unmount()
45 | end)
46 | end
47 |
48 | function ContainerLayout:_create_main_popup()
49 | self.main_popup = Popup({
50 | enter = true,
51 | focusable = true,
52 | border = {
53 | style = 'rounded',
54 | text = {
55 | top = 'Docker Containers',
56 | top_align = 'center',
57 | bottom = ': Expand, : Expand All, : Collapse, : Collapse All'
58 | },
59 | },
60 | })
61 | end
62 |
63 | function ContainerLayout:_create_log_popup()
64 | self.log_popup = Popup({
65 | border = {
66 | text = {
67 | top = 'Logs',
68 | top_align = 'center',
69 | },
70 | style = 'double'
71 | }
72 | })
73 | end
74 |
75 | function ContainerLayout:get_containers()
76 | docker({
77 | 'container',
78 | 'ls',
79 | '-a',
80 | '--format={"id": {{json .ID}}, "name": {{json .Names}}, "image": {{json .Image}}, "command": {{json .Command}}, "status": {{json .Status}}, "networks": {{json .Networks}}, "ports": {{json .Ports}}}'
81 | }, {
82 | on_exit = function (j)
83 | local result = j:result()
84 | if result ~= nil then
85 | local containers = {}
86 | for _, value in ipairs(result) do
87 | if value ~= nil then
88 | local container = vim.json.decode(value)
89 | table.insert(containers, container)
90 | end
91 | end
92 | self._containers(containers)
93 | end
94 | end
95 | }):start()
96 | return self._containers
97 | end
98 |
99 | function ContainerLayout:_render_containers(containers)
100 | local old_nodes = self.tree:get_nodes()
101 | tree_utils.remove_nodes(self.tree)
102 | for _, container in ipairs(containers) do
103 | local text = ''
104 | if string.find(container.status, 'Up') then
105 | text = container.name .. ' 🟢'
106 | else
107 | text = container.name .. ' 🔴'
108 | end
109 |
110 | local node = Tree.Node({ text = text, container = container }, {
111 | Tree.Node({ text = '[ID] ' .. container.id }),
112 | Tree.Node({ text = '[Image] ' .. container.image }),
113 | Tree.Node({ text = '[Command] ' .. container.command }),
114 | Tree.Node({ text = '[Status] ' .. container.status }),
115 | Tree.Node({ text = '[Networks] ' .. container.networks }),
116 | Tree.Node({ text = '[Ports] ' .. container.ports }),
117 | })
118 | self.tree:add_node(node)
119 | if next(old_nodes) ~= nil then
120 | for _, old_node in ipairs(old_nodes) do
121 | -- if the node was expanded before it was cleared, expand it again
122 | if old_node.container.id == node.container.id then
123 | if old_node:is_expanded() then
124 | node:expand()
125 | end
126 | end
127 | end
128 | end
129 | end
130 | vim.schedule(function ()
131 | self.tree:render()
132 | end)
133 | end
134 |
135 | function ContainerLayout:show_containers()
136 | if self.mounted == false then
137 | self:mount()
138 | self.tree = Tree({ winid = self.main_popup.winid})
139 | popup_keymaps.create_keymaps(self.main_popup, self.keymaps, self.tree, self)
140 | self:_setup_main_popup_on_bufleave()
141 | self.mounted = true
142 | end
143 | self.main_popup_timer = vim.loop.new_timer()
144 | self.main_popup_timer:start(0, 5000, vim.schedule_wrap(function ()
145 | self:get_containers():subscribe(vim.schedule_wrap(function (containers)
146 | self:_render_containers(containers)
147 | end))
148 | end))
149 | end
150 |
151 | return ContainerLayout
152 |
--------------------------------------------------------------------------------
/lua/nvim-docker/container-logs.lua:
--------------------------------------------------------------------------------
1 | local rx = require('reactivex')
2 | local docker = require('nvim-docker.docker')
3 |
4 | local _M = {
5 | _timer = nil,
6 | _logs_subscription = nil
7 | }
8 |
9 | local function reset_timer()
10 | if _M._timer ~= nil then
11 | _M._timer:close()
12 | _M._timer = nil
13 | end
14 | end
15 |
16 | local function reset_logs_subscription()
17 | if _M._logs_subscription ~= nil then
18 | _M._logs_subscription:unsubscribe()
19 | _M._logs_subscription = nil
20 | end
21 | end
22 |
23 | function _M.teardown()
24 | reset_timer()
25 | reset_logs_subscription()
26 | end
27 |
28 | function _M.follow_logs(container_name, cb)
29 | _M.teardown()
30 | local logs_stream = rx.Subject.create()
31 | _M._logs_subscription = logs_stream:subscribe(function (logs)
32 | cb(logs)
33 | end)
34 | _M._timer = vim.loop.new_timer()
35 | _M._timer:start(0, 5000, vim.schedule_wrap(function ()
36 | -- FORMAT: yyyy-mm-ddThh:mm:ssZ
37 | local start_from = os.date('%Y-%m-%dT%H:%M:%SZ')
38 | print('container_name: ' .. container_name .. 'time: ' .. start_from)
39 | docker(
40 | {'logs', '--since', start_from, container_name },
41 | {
42 | on_exit = vim.schedule_wrap(function (job)
43 | logs_stream(job:result())
44 | end)
45 | }):start()
46 | end))
47 | end
48 |
49 | return _M
50 |
--------------------------------------------------------------------------------
/lua/nvim-docker/containers.lua:
--------------------------------------------------------------------------------
1 | local extra_keymaps = require('nvim-docker.container-keymaps').extra_keymaps
2 | local ContainerLayout = require('nvim-docker.container-layout')
3 | local _M = {}
4 |
5 | function _M.list_containers()
6 | local layout = ContainerLayout({}, extra_keymaps)
7 | layout:show_containers()
8 | end
9 |
10 | return _M
11 |
--------------------------------------------------------------------------------
/lua/nvim-docker/docker.lua:
--------------------------------------------------------------------------------
1 | local Job = require('plenary.job')
2 |
3 | local function docker(args, options)
4 | local job_options = vim.tbl_deep_extend('force', options or {}, {
5 | command = 'docker',
6 | args = args
7 | })
8 | return Job:new(job_options)
9 | end
10 |
11 | return docker
12 |
--------------------------------------------------------------------------------
/lua/nvim-docker/popup-keymaps.lua:
--------------------------------------------------------------------------------
1 | local _M = {}
2 |
3 | -- local help_popup = Popup({
4 | -- enter = true,
5 | -- focusable = true,
6 | -- border = {
7 | -- style = 'rounded',
8 | -- text = {
9 | -- top = 'Help',
10 | -- top_align = 'center',
11 | -- },
12 | -- },
13 | -- position = '50%',
14 | -- size = {
15 | -- width = '40%',
16 | -- height = '60%',
17 | -- },
18 | -- })
19 |
20 | function _M.create_keymaps(popup, extra_keymaps, tree, layout)
21 | local tree_utils = require('nvim-docker.tree-utils')
22 | local map_options = { remap = false, nowait = true }
23 |
24 | -- help_popup:map('n', '?', function ()
25 | -- help_popup:unmount()
26 | -- popup:update_layout({
27 | -- position = '50%',
28 | -- size = {
29 | -- width = '80%',
30 | -- height = '60%',
31 | -- },
32 | -- })
33 | -- popup:on(event.BufLeave, function()
34 | -- state.popup = nil
35 | -- state.tree = nil
36 | -- local function unmount()
37 | -- state.popup_timer:close()
38 | -- popup:unmount()
39 | -- end
40 | -- pcall(unmount)
41 | -- end)
42 | -- end)
43 |
44 | -- popup:map('n', '?', function ()
45 | -- -- if help_opened == nil then
46 | -- popup:off(event.BufLeave)
47 | -- popup:update_layout({
48 | -- size = {
49 | -- width = '30%',
50 | -- height = '60%'
51 | -- },
52 | -- position = {
53 | -- row = '50%',
54 | -- col = '0%'
55 | -- }
56 | -- })
57 | -- help_popup:mount()
58 | -- if config.extra_keymaps ~= nil then
59 | -- for index, keymap in ipairs(config.extra_keymaps) do
60 | -- vim.api.nvim_buf_set_lines(help_popup.bufnr, index, index + 1, false, {'[Key]: ' .. keymap[2] .. ' ' .. keymap[4]})
61 | -- end
62 | -- end
63 | -- end)
64 |
65 |
66 | -- collapse
67 | popup:map('n', 'h', function()
68 | local node, linenr = tree:get_node()
69 | if not node:has_children() then
70 | node, linenr = tree:get_node(node:get_parent_id())
71 | end
72 | if node and node:collapse() then
73 | vim.api.nvim_win_set_cursor(popup.winid, { linenr, 0 })
74 | tree:render()
75 | end
76 | end, map_options)
77 |
78 | -- collapse all
79 | popup:map('n', 'H', function ()
80 | tree_utils.collapse_all_nodes(tree)
81 | end, map_options)
82 |
83 | -- expand
84 | popup:map("n", "l", function()
85 | local node, linenr = tree:get_node()
86 | if not node:has_children() then
87 | node, linenr = tree:get_node(node:get_parent_id())
88 | end
89 | if node and node:expand() then
90 | if not node.checked then
91 | node.checked = true
92 | end
93 |
94 | vim.api.nvim_win_set_cursor(popup.winid, { linenr, 0 })
95 | tree:render()
96 | end
97 | end, map_options)
98 |
99 | -- expand all
100 | popup:map('n', 'L', function ()
101 | tree_utils.expand_all_nodes(tree)
102 | end, map_options)
103 |
104 | if extra_keymaps ~= nil then
105 | for _, keymap in ipairs(extra_keymaps) do
106 | popup:map(
107 | keymap[1],
108 | keymap[2],
109 | function () keymap[3]({popup = popup, tree = tree, layout = layout}) end,
110 | map_options
111 | )
112 | end
113 | end
114 | end
115 |
116 | return _M
117 |
--------------------------------------------------------------------------------
/lua/nvim-docker/tree-utils.lua:
--------------------------------------------------------------------------------
1 | local _M = {}
2 |
3 | function _M.get_expanded_nodes(tree)
4 | local nodes = {}
5 |
6 | local function process(node)
7 | if node:is_expanded() then
8 | table.insert(nodes, node)
9 |
10 | if node:has_children() then
11 | for _, child in ipairs(_M.tree:get_nodes(node:get_id())) do
12 | process(child)
13 | end
14 | end
15 | end
16 | end
17 |
18 | for _, node in ipairs(tree:get_nodes()) do
19 | process(node)
20 | end
21 |
22 | return nodes
23 | end
24 |
25 | function _M.collapse_all_nodes(tree)
26 | local nodes = tree:get_nodes()
27 | for _, node in ipairs(nodes) do
28 | local id = node:get_id()
29 | node:collapse(id)
30 | end
31 | tree:render()
32 |
33 | -- If you want to expand the root
34 | -- local root = tree:get_nodes()[1]
35 | -- root:expand()
36 | end
37 |
38 | function _M.expand_all_nodes(tree)
39 | local nodes = tree:get_nodes()
40 | for _, node in ipairs(nodes) do
41 | local id = node:get_id()
42 | node:expand(id)
43 | end
44 | tree:render()
45 | -- If you want to expand the root
46 | -- local root = tree:get_nodes()[1]
47 | -- root:expand()
48 | end
49 |
50 | function _M.remove_nodes(tree)
51 | local nodes = tree:get_nodes()
52 | if next(nodes) ~= nil then
53 | for _, node in ipairs(nodes) do
54 | if type(node.children) == 'table' and next(node.children) then
55 | for _, child in ipairs(node.children) do
56 | tree:remove_node(child:get_id())
57 | end
58 | end
59 | tree:remove_node(node:get_id())
60 | end
61 | end
62 | end
63 |
64 | return _M
65 |
--------------------------------------------------------------------------------