Lua에서 neovim 플러그인을 작성하는 방법
63355 단어 programmingvimwebdevtutorial
플러그인 디렉터리 구조
우리의 플러그인은 적어도 두 개의 디렉터리가 있어야 한다.
plugin
우리는 그것의 메인 파일과 lua
전체 코드 라이브러리를 가지고 있다.물론, 만약 우리가 정말 그것을 원한다면, 우리는 모든 것을 하나의 서류에 넣을 수 있지만, 이 녀석(또는 소녀)이 되지 마세요.그래서plugin/whid.vim
와lua/whid.lua
가능합니다.우리는 다음과 같은 측면에서 착수할 수 있다." in plugin/whid.vim
if exists('g:loaded_whid') | finish | endif " prevent loading file twice
let s:save_cpo = &cpo " save user coptions
set cpo&vim " reset them to defaults
" command to run our plugin
command! Whid lua require'whid'.whid()
let &cpo = s:save_cpo " and restore after
unlet s:save_cpo
let g:loaded_whid = 1
let s:save_cpo = &cpo
플러그인을 방해하는 사용자 정의 coptions
(단일 문자 플래그 시퀀스) 를 방지하는 일반적인 방법입니다.우리 자신의 목적상 이 줄이 부족하면 나쁘지 않을 수도 있지만, 이것은 좋은 방법으로 여겨진다. (적어도vim 도움말 파일에 따라)그리고 command! Whid lua require'whid'.whid()
플러그인이 필요한 루아 모듈과 주요 기능을 호출합니다.부동 창
좋아, 우리 재미있는 일부터 시작합시다.우리는 물건을 전시할 수 있는 곳을 만들어야 한다.고맙습니다.neovim(지금도vim)은 부동창이라고 불리는 깔끔한 특성을 가지고 있습니다.운영 체제에 있는 것처럼 다른 창 위에 표시되는 창입니다.
-- in lua/whid.lua
local api = vim.api
local buf, win
local function open_window()
buf = api.nvim_create_buf(false, true) -- create new emtpy buffer
api.nvim_buf_set_option(buf, 'bufhidden', 'wipe')
-- get dimensions
local width = api.nvim_get_option("columns")
local height = api.nvim_get_option("lines")
-- calculate our floating window size
local win_height = math.ceil(height * 0.8 - 4)
local win_width = math.ceil(width * 0.8)
-- and its starting position
local row = math.ceil((height - win_height) / 2 - 1)
local col = math.ceil((width - win_width) / 2)
-- set some options
local opts = {
style = "minimal",
relative = "editor",
width = win_width,
height = win_height,
row = row,
col = col
}
-- and finally create it with buffer attached
win = api.nvim_open_win(buf, true, opts)
end
이 파일의 맨 위에서, 우리는 가장 높은 범위 내에서 win
과 buf
변수를 정의했는데, 이것은 보통 다른 함수에 인용된다.비어 있습니다. 이 때, 버퍼는 우리가 결과를 놓을 곳입니다.나열되지 않은 버퍼 (첫 번째 매개 변수) 와 임시 버퍼 (두 번째 매개 변수, 참조 :h scratch-buffer
로 생성됩니다.숨길 때 삭제bufhidden = wipe
로 설정합니다.nvim_open_win(buf, true, opts)
를 사용하여 새 창을 만들고 이전에 만든 버퍼를 이 창에 연결합니다.두 번째 논점은 새로운 창을 초점으로 만들었다.width
과height
는 모두 말하지 않아도 안다.row
및 col
는 편집기relative = "editor"
의 왼쪽 상단에서 계산된 창의 시작 위치입니다.style = "minimal"
창 모양을 구성하는 데 편리한 옵션입니다. 여기에서 줄 번호나 맞춤법 오류 강조 표시와 같은 불필요한 옵션을 사용하지 않습니다.지금 우리는 부동 창이 생겼지만, 우리는 그것을 더욱 좋아 보일 수 있다.Neovim은 현재 border 같은 작은 위젯을 지원하지 않기 때문에 우리가 직접 만들어야 합니다.이것은 매우 간단하다.우리는 첫 번째보다 조금 큰 다른 부동창이 필요하다. 그 밑에 놓아라.
local border_opts = {
style = "minimal",
relative = "editor",
width = win_width + 2,
height = win_height + 2,
row = row - 1,
col = col - 1
}
우리는 네모난 그림 문자로 그것을 채울 것이다.local border_buf = api.nvim_create_buf(false, true)
local border_lines = { '╔' .. string.rep('═', win_width) .. '╗' }
local middle_line = '║' .. string.rep(' ', win_width) .. '║'
for i=1, win_height do
table.insert(border_lines, middle_line)
end
table.insert(border_lines, '╚' .. string.rep('═', win_width) .. '╝')
api.nvim_buf_set_lines(border_buf, 0, -1, false, border_lines)
-- set bufer's (border_buf) lines from first line (0) to last (-1)
-- ignoring out-of-bounds error (false) with lines (border_lines)
물론 우리는 정확한 순서에 따라 창문을 열어야 한다.그리고 하나 더.두 창문은 시종 함께 닫아야 한다.만약 첫 번째 폐쇄 이후에도 국경이 여전히 존재한다면, 그것은 매우 이상할 것이다.현재viml 자동 명령이 가장 좋은 해결 방안이다.local border_win = api.nvim_open_win(border_buf, true, border_opts)
win = api.nvim_open_win(buf, true, opts)
api.nvim_command('au BufWipeout <buffer> exe "silent bwipeout! "'..border_buf)
데이터 가져오기
우리의 플러그인은 우리가 처리한 최신 파일을 표시하는 데 목적을 두고 있다.우리는 간단한git 명령을 사용하여 이 점을 실현할 것이다.유사:
git diff-tree --no-commit-id --name-only -r HEAD
함수를 만듭니다. 함수는 예쁜 창에 데이터를 넣을 것입니다.우리는 그것을 자주 호출할 것이다. 따라서 우리는 그것을 명명할 것이다 update_view
.local function update_view()
-- we will use vim systemlist function which run shell
-- command and return result as list
local result = vim.fn.systemlist('git diff-tree --no-commit-id --name-only -r HEAD')
-- with small indentation results will look better
for k,v in pairs(result) do
result[k] = ' '..result[k]
end
api.nvim_buf_set_lines(buf, 0, -1, false, result)
end
은마르코프 모형...만약 우리가 현재 파일만 찾을 수 있다면, 그것은 그다지 불편하다.보기를 업데이트하기 위해 이 함수를 직접 호출할 것이기 때문에, 파라미터를 받아들이고, 비교적 오래되거나 새로운 상태를 표시할 것인지에 대한 정보를 제공해야 합니다.local position = 0
local function update_view(direction)
position = position + direction
if position < 0 then position = 0 end -- HEAD~0 is the newest state
local result = vim.fn.systemlist('git diff-tree --no-commit-id --name-only -r HEAD~'..position)
-- ... rest of the code
end
너는 여기에 또 무엇이 부족한지 아니?우리 플러그인의 제목입니다.가운데에 있었어!이 함수는 우리가 일부 텍스트를 중간에 두는 것을 도울 것이다.local function center(str)
local width = api.nvim_win_get_width(0)
local shift = math.floor(width / 2) - math.floor(string.len(str) / 2)
return string.rep(' ', shift) .. str
end
api.nvim_buf_set_lines(buf, 0, -1, false, {
center('What have i done?'),
center('HEAD~'..position),
''
})
end
포인트가 좋을 거예요.우리는 몇 가지 옵션을 선택할 수 있다. 사용자 정의 문법 파일 (줄 번호에 따라 패턴을 일치시킬 수 있음) 을 정의하거나 일반 텍스트 대신 가상 텍스트 주석을 사용하거나.위치 기반 강조 표시nvim_buf_add_highlight
를 사용할 수 있습니다.그러나 우선, 우리는 우리의 하이라이트를 발표해야 한다.색상을 설정하는 대신 기존 하이라이트 그룹에 연결합니다.이렇게 하면 사용자 색상과 일치합니다." in plugin/whid.vim after set cpo&vim
hi def link WhidHeader Number
hi def link WhidSubHeader Identifier
이제 강조 표시를 추가합니다.api.nvim_buf_add_highlight(buf, -1, 'WhidHeader', 0, 0, -1)
api.nvim_buf_add_highlight(buf, -1, 'WhidSubHeader', 1, 0, -1)
우리는 그룹화되지 않은 하이라이트 buf
로 버퍼 -1
에 하이라이트를 추가합니다.우리는 이 곳에서 이름 공간 id를 전달할 수 있습니다. 이것은 그룹의 모든 강조 표시를 한 번에 제거할 수 있지만, 우리의 경우, 우리는 이렇게 할 필요가 없습니다.다음은 줄 번호입니다. 마지막 두 개의 매개 변수는 시작과 끝 (바이트 인덱스) 열 범위입니다.전체 함수는 다음과 같습니다.
local function update_view(direction)
-- Is nice to prevent user from editing interface, so
-- we should enabled it before updating view and disabled after it.
api.nvim_buf_set_option(buf, 'modifiable', true)
position = position + direction
if position < 0 then position = 0 end
local result = vim.fn.systemlist('git diff-tree --no-commit-id --name-only -r HEAD~'..position)
for k,v in pairs(result) do
result[k] = ' '..result[k]
end
api.nvim_buf_set_lines(buf, 0, -1, false, {
center('What have i done?'),
center('HEAD~'..position),
''
})
api.nvim_buf_set_lines(buf, 3, -1, false, result)
api.nvim_buf_add_highlight(buf, -1, 'WhidHeader', 0, 0, -1)
api.nvim_buf_add_highlight(buf, -1, 'whidSubHeader', 1, 0, -1)
api.nvim_buf_set_option(buf, 'modifiable', false)
end
사용자 입력
이제 우리는 플러그인을 상호작용을 가지게 해야 한다.현재 미리 보기의 상태를 변경하거나 파일을 선택하고 열 수 있는 간단한 기능만 있습니다.우리의 플러그인은 맵을 통해 사용자의 입력을 받을 것입니다.키를 누르면 동작을 촉발합니다.LuaAPI에서 매핑을 정의하는 방법을 살펴보겠습니다.
api.nvim_buf_set_keymap(buf, 'n', 'x', ':echo "wow!"<cr>', { nowait = true, noremap = true, silent = true })
첫 번째 매개 변수는 보통 버퍼입니다.이 매핑의 범위는 그것으로 한정될 것이다.다음은 모드의 짧은 이름입니다.우리는 정상 모드 n
에서 우리의 모든 맵을 정의했다.그리고 "오른쪽"키 조합에 비추는 "좌"키 조합 (나는 예시로 x
을 선택합니다) (neovim에게 명령행 모드에 들어가서 viml을 입력하고 enter<cr>
를 누르라고 알려줍니다.)마지막으로 선택의 여지가 있다.우리는neovim이 일치하는 모드에서 바로 맵을 터치하기를 원합니다. 따라서 다른 맵 nowait
을 통해 맵을 터치하지 않고 사용자에게 입력 noremap
을 표시하지 않도록 로고를 설정합니다.이것은 매우 긴 선이기 때문에 우리는 몇 개의 쓰기 조작을 절약하기 위해 수조를 사용한다.local function set_mappings()
local mappings = {
['['] = 'update_view(-1)',
[']'] = 'update_view(1)',
['<cr>'] = 'open_file()',
h = 'update_view(-1)',
l = 'update_view(1)',
q = 'close_window()',
k = 'move_cursor()'
}
for k,v in pairs(mappings) do
api.nvim_buf_set_keymap(buf, 'n', k, ':lua require"whid".'..v..'<cr>', {
nowait = true, noremap = true, silent = true
})
end
end
사용하지 않은 키를 비활성화할 수도 있습니다.local other_chars = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
}
for k,v in ipairs(other_chars) do
api.nvim_buf_set_keymap(buf, 'n', v, '', { nowait = true, noremap = true, silent = true })
api.nvim_buf_set_keymap(buf, 'n', v:upper(), '', { nowait = true, noremap = true, silent = true })
api.nvim_buf_set_keymap(buf, 'n', '<c-'..v..'>', '', { nowait = true, noremap = true, silent = true })
end
공공 기능
좋습니다. 하지만 맵에 새로운 함수가 언급되었습니다.그것들을 좀 봅시다.
local function close_window()
api.nvim_win_close(win, true)
end
-- Our file list start at line 4, so we can prevent reaching above it
-- from bottm the end of the buffer will limit movment
local function move_cursor()
local new_pos = math.max(4, api.nvim_win_get_cursor(win)[1] - 1)
api.nvim_win_set_cursor(win, {new_pos, 0})
end
-- Open file under cursor
local function open_file()
local str = api.nvim_get_current_line()
close_window()
api.nvim_command('edit '..str)
end
우리의 서류 명세서는 매우 간단하다.우리는 커서 밑에 한 줄만 그려서 네비엠에게 편집하라고 알려주면 된다.물론 우리는 더욱 복잡한 메커니즘을 세울 수 있다.우리는 줄 번호 (심지어 열) 를 얻어서 그것에 따라 특정한 조작을 촉발할 수 있다.그것은 보기와 논리를 분리할 수 있게 할 것이다.하지만 우리의 목적으로는 충분하다.그러나 만약 우리가 먼저 이 함수를 내보내지 않는다면, 그 중의 어떤 함수도 호출할 수 없다.파일의 밑에 공공 사용 가능한 함수가 있는 관련 그룹을 되돌려줍니다.
return {
whid = whid,
update_view = update_view,
open_file = open_file,
move_cursor = move_cursor,
close_window = close_window
}
물론 주요 기능도 있습니다!local function whid()
position = 0 -- if you want to preserve last displayed state just omit this line
open_window()
set_mappings()
update_view(0)
api.nvim_win_set_cursor(win, {4, 0}) -- set cursor on first list entry
end
전체 플러그인...
... 약간의 개선을 통해 (평론을 찾아서 그것들을 찾을 수 있다.)
" plugin/whid.vim
if exists('g:loaded_whid') | finish | endif
let s:save_cpo = &cpo
set cpo&vim
hi def link WhidHeader Number
hi def link WhidSubHeader Identifier
command! Whid lua require'whid'.whid()
let &cpo = s:save_cpo
unlet s:save_cpo
let g:loaded_whid = 1
-- lua/whid.lua
local api = vim.api
local buf, win
local position = 0
local function center(str)
local width = api.nvim_win_get_width(0)
local shift = math.floor(width / 2) - math.floor(string.len(str) / 2)
return string.rep(' ', shift) .. str
end
local function open_window()
buf = api.nvim_create_buf(false, true)
local border_buf = api.nvim_create_buf(false, true)
api.nvim_buf_set_option(buf, 'bufhidden', 'wipe')
api.nvim_buf_set_option(buf, 'filetype', 'whid')
local width = api.nvim_get_option("columns")
local height = api.nvim_get_option("lines")
local win_height = math.ceil(height * 0.8 - 4)
local win_width = math.ceil(width * 0.8)
local row = math.ceil((height - win_height) / 2 - 1)
local col = math.ceil((width - win_width) / 2)
local border_opts = {
style = "minimal",
relative = "editor",
width = win_width + 2,
height = win_height + 2,
row = row - 1,
col = col - 1
}
local opts = {
style = "minimal",
relative = "editor",
width = win_width,
height = win_height,
row = row,
col = col
}
local border_lines = { '╔' .. string.rep('═', win_width) .. '╗' }
local middle_line = '║' .. string.rep(' ', win_width) .. '║'
for i=1, win_height do
table.insert(border_lines, middle_line)
end
table.insert(border_lines, '╚' .. string.rep('═', win_width) .. '╝')
api.nvim_buf_set_lines(border_buf, 0, -1, false, border_lines)
local border_win = api.nvim_open_win(border_buf, true, border_opts)
win = api.nvim_open_win(buf, true, opts)
api.nvim_command('au BufWipeout <buffer> exe "silent bwipeout! "'..border_buf)
api.nvim_win_set_option(win, 'cursorline', true) -- it highlight line with the cursor on it
-- we can add title already here, because first line will never change
api.nvim_buf_set_lines(buf, 0, -1, false, { center('What have i done?'), '', ''})
api.nvim_buf_add_highlight(buf, -1, 'WhidHeader', 0, 0, -1)
end
local function update_view(direction)
api.nvim_buf_set_option(buf, 'modifiable', true)
position = position + direction
if position < 0 then position = 0 end
local result = vim.fn.systemlist('git diff-tree --no-commit-id --name-only -r HEAD~'..position)
if #result == 0 then table.insert(result, '') end -- add an empty line to preserve layout if there is no results
for k,v in pairs(result) do
result[k] = ' '..result[k]
end
api.nvim_buf_set_lines(buf, 1, 2, false, {center('HEAD~'..position)})
api.nvim_buf_set_lines(buf, 3, -1, false, result)
api.nvim_buf_add_highlight(buf, -1, 'whidSubHeader', 1, 0, -1)
api.nvim_buf_set_option(buf, 'modifiable', false)
end
local function close_window()
api.nvim_win_close(win, true)
end
local function open_file()
local str = api.nvim_get_current_line()
close_window()
api.nvim_command('edit '..str)
end
local function move_cursor()
local new_pos = math.max(4, api.nvim_win_get_cursor(win)[1] - 1)
api.nvim_win_set_cursor(win, {new_pos, 0})
end
local function set_mappings()
local mappings = {
['['] = 'update_view(-1)',
[']'] = 'update_view(1)',
['<cr>'] = 'open_file()',
h = 'update_view(-1)',
l = 'update_view(1)',
q = 'close_window()',
k = 'move_cursor()'
}
for k,v in pairs(mappings) do
api.nvim_buf_set_keymap(buf, 'n', k, ':lua require"whid".'..v..'<cr>', {
nowait = true, noremap = true, silent = true
})
end
local other_chars = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
}
for k,v in ipairs(other_chars) do
api.nvim_buf_set_keymap(buf, 'n', v, '', { nowait = true, noremap = true, silent = true })
api.nvim_buf_set_keymap(buf, 'n', v:upper(), '', { nowait = true, noremap = true, silent = true })
api.nvim_buf_set_keymap(buf, 'n', '<c-'..v..'>', '', { nowait = true, noremap = true, silent = true })
end
end
local function whid()
position = 0
open_window()
set_mappings()
update_view(0)
api.nvim_win_set_cursor(win, {4, 0})
end
return {
whid = whid,
update_view = update_view,
open_file = open_file,
move_cursor = move_cursor,
close_window = close_window
}
이제 루아네옴 스크립트를 위한 간단한 TUI를 작성할 수 있는 기본 지식을 갖추어야 합니다.즐겁게 놀다코드도 여기서 찾을 수 있습니다https://github.com/rafcamlet/nvim-whid
Reference
이 문제에 관하여(Lua에서 neovim 플러그인을 작성하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/2nit/how-to-write-neovim-plugins-in-lua-5cca텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)