terminal.lua (2795B)
1 --- Dispatchers for LSP message types. 2 --- @class (private) State 3 --- @field win integer? 4 --- @field buf integer 5 --- @field chan integer 6 --- @field last_command string? 7 local State = { 8 } 9 10 function State:is_open() 11 return self.win and vim.api.nvim_win_is_valid(self.win) 12 end 13 14 function State:is_valid() 15 return self.buf and vim.api.nvim_buf_is_valid(self.buf) and self.chan 16 end 17 18 local M = {} 19 20 M.toggle = function() 21 if State:is_open() then 22 vim.api.nvim_win_close(State.win, true) 23 State.win = nil 24 return 25 end 26 27 if State:is_valid() then 28 State.win = vim.api.nvim_open_win(State.buf, false, { split = 'below', height = 12 }) 29 30 vim.api.nvim_set_current_win(State.win) 31 32 vim.cmd.normal('G') 33 vim.cmd.wincmd('p') 34 else 35 State.buf = vim.api.nvim_create_buf(false, true) 36 State.win = vim.api.nvim_open_win(State.buf, false, { split = 'below', height = 12 }) 37 38 vim.api.nvim_set_current_win(State.win) 39 vim.cmd.term() 40 State.chan = vim.opt.channel:get() 41 vim.api.nvim_buf_set_name(State.buf, 'terminal') 42 43 vim.cmd.normal('G') 44 vim.cmd.wincmd('p') 45 end 46 end 47 48 -- Closes the window and deletes the buffer. This entirely resets the term state 49 M.exit = function() 50 if State:is_open() then 51 vim.api.nvim_win_close(State.win, true) 52 State.win = nil 53 end 54 55 if State:is_valid() then 56 vim.api.nvim_buf_delete(State.buf, { force = true }) 57 end 58 59 State.buf = nil 60 State.chan = nil 61 end 62 63 -- Takes a command as a string and runs it in the terminal buffer. If the window is closed, it will be toggled 64 ---@param cmd string 65 M.run = function(cmd) 66 if not State:is_open() and not State:is_valid() then 67 M.toggle() 68 elseif State.last_command then 69 -- Send <C-c> to make sure any on-going commands like log tails are stopped before running the new command 70 vim.api.nvim_chan_send(State.chan, '\003') 71 end 72 73 State.last_command = cmd 74 vim.api.nvim_chan_send(State.chan, ' ' .. cmd .. '\r') 75 end 76 77 -- Runs the last command again 78 M.rerun = function() 79 if not State.last_command then 80 print('Last command empty') 81 return 82 end 83 M.run(State.last_command) 84 M.catchup() 85 return true 86 end 87 88 -- Jumps to the terminal window and enters insert mode. If called from the terminal window, it will jump back to the 89 -- previous window 90 M.interactive = function() 91 if not State:is_open() then 92 M.toggle() 93 end 94 95 if vim.api.nvim_get_current_win() == State.win then 96 vim.cmd.wincmd('p') 97 else 98 vim.api.nvim_set_current_win(State.win) 99 vim.cmd.startinsert() 100 end 101 end 102 103 -- Jump to the end of terminal buffer without moving from actual buffer 104 M.catchup = function() 105 if not State:is_open() then 106 M.toggle() 107 end 108 109 if State:is_valid() then 110 vim.api.nvim_buf_call(State.buf, function() 111 vim.cmd.normal('G') 112 end) 113 end 114 end 115 116 return M