-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinit.lua
More file actions
2601 lines (2374 loc) · 90.9 KB
/
init.lua
File metadata and controls
2601 lines (2374 loc) · 90.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
local START_TIME = vim.uv.hrtime() -- 勿調整,用來得知nvim開啟的時間,如果要計算啟動花費時間會有用
-- theme: https://github.com/projekt0n/github-nvim-theme
-- https://github.com/projekt0n/github-nvim-theme/blob/c106c9472154d6b2c74b74565616b877ae8ed31d/README.md?plain=1#L170-L206
vim.cmd('colorscheme github_dark_default') -- 主題要先設定(可以先設定之後再補全它的實作),不然如果自定義的調整在這之前,又會被此蓋掉
local array = require("utils.array")
local completion = require("utils.complete")
local cmdUtils = require("utils.cmd")
local utils = require("utils.utils")
local HOME = os.getenv("HOME")
-- runtimepath
-- local runtimepath = vim.api.nvim_get_option("runtimepath")
local runtimepath = vim.api.nvim_get_option_value("runtimepath", {})
vim.opt.runtimepath = runtimepath .. ",~/.vim,~/.vim/after"
vim.opt.packpath = vim.opt.runtimepath:get()
-- vim
local vimrcPath = HOME .. "/.vimrc"
if vim.fn.filereadable(vimrcPath) == 1 then
vim.cmd("source " .. vimrcPath)
end
-- config
require("config.sign_define")
require("config.options").setup()
require "config.filetype".setup {
(
{
pattern = "*/doc/*.txt",
filetype = "help",
groupName = "DocHelp"
}
)
}
require("config.keymaps").setup()
require("config.commands").setup()
require("config.commands_windows")
require("config.autocmd").setup({
callback = function(m)
vim.api.nvim_create_user_command(
"ToggleFMT",
function()
m.autoReformat = not m.autoReformat
vim.notify("autoReformat: " .. vim.inspect(m.autoReformat), vim.log.levels.INFO)
end,
{ desc = "切換自動格式化" }
)
vim.api.nvim_create_user_command(
"SetAutoFmt",
function(args)
m.autoReformat = args.fargs[1] == "1"
vim.notify("autoReformat: " .. vim.inspect(m.autoReformat), vim.log.levels.INFO)
end,
{
nargs = 1,
complete = function()
return {
"1",
"0"
}
end,
desc = "enable autoReformat"
}
)
vim.api.nvim_create_user_command(
"SetAutoSave",
function(args)
if args.fargs[1] == "-" then
-- toggle
m.autoSave = not m.autoSave
else
m.autoSave = args.fargs[1] == "1"
end
vim.notify("autoSave: " .. vim.inspect(m.autoSave), vim.log.levels.INFO)
end,
{
nargs = 1,
complete = function() -- complete 不能直接回傳一個table,一定要用一個function來包裝
return {
"1",
"0",
"-",
}
end,
desc = "enable autoSave"
}
)
vim.keymap.set({ "n" }, "<C-s>",
function()
vim.cmd("SetAutoSave -")
end,
{
-- 自動保存,在頻繁編輯下,一離開insert就保存可能會造成負擔,所以讓其可以被容易切換
desc = "toggle autosave"
}
)
end
})
if vim.uv.os_uname().sysname == "Linux" then
require("config.input").fcitx.setup(
"fcitx5-remote" -- which fcitx5-remote
)
elseif vim.uv.os_uname().sysname == "Darwin" then
require("config.input").sim.setup()
end
local function install_nvimTreesitter()
-- pack/syntax/start/nvim-treesitter
local status_ok, m = pcall(require, "nvim-treesitter.configs")
if not status_ok then
return
end
---@type table
local parser_list = require("nvim-treesitter.parsers").get_parser_configs()
-- ~~https://github.com/nvim-treesitter/nvim-treesitter/blob/42fc28ba918343ebfd5565147a42a26580579482/lua/nvim-treesitter/parsers.lua#L60-L83~~
-- 目前沒有辦法再透過這樣的方式(get_parser_configs)來裝, 因為現行的它在程式中是直接調用,導致: `local parsers = require('nvim-treesitter.parsers')` 得到的內容都是固定的
-- https://github.com/nvim-treesitter/nvim-treesitter/blob/99dfc5acefd7728cec4ad0d0a6a9720f2c2896ff/lua/nvim-treesitter/config.lua#L139-L151
-- 👇 目前以下已無效果
parser_list.strings = { -- :TSInstall strings -- 如果反悔可以用 :TSUninstall strings 來解除
install_info = {
revision = '62ee9e1f538df04a178be7090a1428101481d714',
url = "https://github.com/CarsonSlovoka/tree-sitter-strings",
-- url = vim.fn.expand("~/tree_sitter_strings"), -- 本機的一直沒有嘗試成功🤔
files = { "src/parser.c" },
},
filetype = "strings", -- Neovim filetype
maintainers = { "@Carson" },
}
-- :TSModuleInfo -- 可以查看安裝的情況
-- 底下的內容確定不用加(至少來源從github來是如此)
-- vim.treesitter.language.add('strings',
-- -- { path = vim.fn.expand("~/.config/nvim/pack/syntax/start/nvim-treesitter/parser/strings.so") },
-- -- { path = vim.fn.expand("~/tree-sitter-strings/strings.so") }
-- )
-- 以下沒用
-- if "test" then
-- -- 💡💡 如果只是要讓一個新的項目,沿用某一種已經設計好的filetype, 只需要在 after/syntax/ 之中新增相對應的項目即可,例如: after/syntax/ttx/syntax.lua
--
-- -- 新增一個ttx的解析,其本質與xml是相同的,只是讓filetype可以真正的被設定成ttx也能有效果(不想要用xml來表示)
-- parser_list.ttx = { -- https://github.com/nvim-treesitter/nvim-treesitter/blob/42fc28ba918343ebfd5565147a42a26580579482/lua/nvim-treesitter/parsers.lua#L2678-L2685
-- install_info = {
-- url = "https://github.com/tree-sitter-grammars/tree-sitter-xml",
-- files = { "src/parser.c", "src/scanner.c" },
-- location = "xml",
-- },
-- filetype = "ttx", -- 加了也沒用
-- maintainers = { "@ObserverOfTime" },
-- }
--
-- require("nvim-treesitter.parsers")
-- vim.treesitter.language.register("xml", "ttx") -- lang, filetype
-- end
-- 💡 如果只是要syntax的突顯,預設nvim就已經有很多種格式,不再需要特別安裝: https://github.com/neovim/neovim/tree/af6b3d6/runtime/syntax
-- 💡 如果是markdown的codeblock要有突顯,才需要考慮 nvim-treesitter.parsers 安裝, 因為它會有多定義出來的highlight
-- 💡 已存在的第三方parser參考:
-- - ~~舊版: https://github.com/nvim-treesitter/nvim-treesitter/blob/42fc28ba918343ebfd5565147a42a26580579482/lua/nvim-treesitter/parsers.lua#L69-L2764~~
-- - 新版(有新增該版本的雜湊值): https://github.com/nvim-treesitter/nvim-treesitter/blob/99dfc5acefd7728cec4ad0d0a6a9720f2c2896ff/lua/nvim-treesitter/parsers.lua#L1-L2693
-- Caution: ensure_installed已經不可用: https://github.com/nvim-treesitter/nvim-treesitter/blob/99dfc5acefd7728cec4ad0d0a6a9720f2c2896ff/README.md?plain=1#L59-L69
m.setup { -- pack/syntax/start/nvim-treesitter/lua/configs.lua
ensure_installed = { -- 寫在這邊的項目就不需要再用 :TSInstall 去裝,它會自動裝
-- ~~:TSModuleInfo 也可以找有哪些內容能裝~~ 已經沒有作用
-- :TSInstall bash lua go gotmpl python xml json jsonc markdown markdown_inline dart elixir sql diff html latex yaml
-- :TSInstall all # 👈 Warn: 不要用這個,會裝所有可以裝的項目,會太多
"bash",
"lua",
"go",
"gotmpl", -- https://github.com/ngalaiko/tree-sitter-go-template -- https://github.com/nvim-treesitter/nvim-treesitter/blob/42fc28ba918343ebfd5565147a42a26580579482/lua/nvim-treesitter/parsers.lua#L896-L902
"python", -- 為了在markdown突顯
-- "ttx",
"xml",
-- vscode-json-language-server 就有json, jsonc的lsp, 不過沒有json5的lsp
"json", -- 為了md上的codeblock突顯
"jsonc", -- 高亮可以 https://github.com/nvim-treesitter/nvim-treesitter/blob/42fc28ba918343ebfd5565147a42a26580579482/lua/nvim-treesitter/parsers.lua#L1212-L1220
-- "json5", -- 覺得它的高亮不好,並且也沒有lsp的支持 -- https://github.com/nvim-treesitter/nvim-treesitter/blob/42fc28ba918343ebfd5565147a42a26580579482/lua/nvim-treesitter/parsers.lua#L1204-L1210
"markdown", "markdown_inline",
-- "strings" -- ~/.config/nvim/pack/syntax/start/nvim-treesitter/parser/strings.so 會在此地方產生相關的so文件
"dart",
"swift",
"elixir", -- 可用在vhs的demo.tap上: https://github.com/charmbracelet/vhs/blob/517bcda0faf416728bcf6b7fe489eb0e2469d9b5/README.md?plain=1#L719-L737
"sql", -- 獲得比較好的highlight
"diff", -- gitdiff: https://github.com/the-mikedavis/tree-sitter-diff (目前前面不可以有多的空白)
"html",
"latex",
"yaml"
},
sync_install = false,
auto_install = false,
ignore_install = {},
modules = {},
highlight = {
enable = true,
additional_vim_regex_highlighting = false,
},
fold = {
-- vim.opt.foldmethod = "expr"
-- vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
enable = true,
}
}
end
local function install_nvimTreesitterContext()
local status_ok, m = pcall(require, "treesitter-context")
if not status_ok then
return
end
m.setup {
enable = true, -- Enable this plugin (Can be enabled/disabled later via commands): TSContext: enable, disable, toggle
multiwindow = false, -- Enable multiwindow support.
max_lines = 0, -- How many lines the window should span. Values <= 0 mean no limit.
min_window_height = 0, -- Minimum editor window height to enable context. Values <= 0 mean no limit.
line_numbers = true,
multiline_threshold = 20, -- Maximum number of lines to show for a single context
trim_scope = 'outer', -- Which context lines to discard if `max_lines` is exceeded. Choices: 'inner', 'outer'
mode = 'cursor', -- Line used to calculate context. Choices: 'cursor', 'topline'
-- Separator between context and content. Should be a single character string, like '-'.
-- When separator is set, the context will only show up when there are at least 2 lines above cursorline.
separator = nil,
zindex = 20, -- The Z-index of the context window
on_attach = nil, -- (fun(buf: integer): boolean) return false to disable attaching
}
end
local function install_nvimTreesitterTextobjects()
if not pcall(require, "nvim-treesitter-textobjects") then
vim.notify("Failed to load nvim-treesitter-textobjects", vim.log.levels.WARN)
return
end
-- Important: 只要使用的時候,有報錯,例如: `Parser could not be created for buffer 81 and language "swift"` 那麼就使用 :TSInstall swift 即可解決
-- https://github.com/nvim-treesitter/nvim-treesitter-textobjects/blob/baa6b4ec28c8be5e4a96f9b1b6ae9db85ec422f8/README.md?plain=1#L43-L163
-- Tip: 也可以參考 [minimal_init.lua](https://github.com/nvim-treesitter/nvim-treesitter-textobjects/blob/baa6b4ec28c8be5e4a96f9b1b6ae9db85ec422f8/scripts/minimal_init.lua#L28-L436)
-- ~/.config/nvim/pack/syntax/start/nvim-treesitter-textobjects/scripts/minimal_init.lua
require("nvim-treesitter-textobjects").setup {
select = {
-- Automatically jump forward to textobj, similar to targets.vim
lookahead = true,
-- You can choose the select mode (default is charwise 'v')
--
-- Can also be a function which gets passed a table with the keys
-- * query_string: eg '@function.inner'
-- * method: eg 'v' or 'o'
-- and should return the mode ('v', 'V', or '<c-v>') or a table
-- mapping query_strings to modes.
selection_modes = {
['@parameter.outer'] = 'v', -- charwise
['@function.outer'] = 'V', -- linewise
-- ['@class.outer'] = '<c-v>', -- blockwise
},
-- If you set this to `true` (default is `false`) then any textobject is
-- extended to include preceding or succeeding whitespace. Succeeding
-- whitespace has priority in order to act similarly to eg the built-in
-- `ap`.
--
-- Can also be a function which gets passed a table with the keys
-- * query_string: eg '@function.inner'
-- * selection_mode: eg 'v'
-- and should return true of false
include_surrounding_whitespace = false,
},
move = {
-- whether to set jumps in the jumplist
set_jumps = true
}
}
-- keymaps: select
-- You can use the capture groups defined in `textobjects.scm`
local select = require "nvim-treesitter-textobjects.select"
vim.keymap.set({ "x", "o" }, "am", function()
select.select_textobject("@function.outer", "textobjects")
end)
vim.keymap.set({ "x", "o" }, "im", function()
select.select_textobject("@function.inner", "textobjects")
end)
vim.keymap.set({ "x", "o" }, "ac", function()
select.select_textobject("@class.outer", "textobjects")
end)
vim.keymap.set({ "x", "o" }, "ic", function()
select.select_textobject("@class.inner", "textobjects")
end)
-- You can also use captures from other query groups like `locals.scm`
-- vim.keymap.set({ "x", "o" }, "as", function()
-- select.select_textobject("@local.scope", "locals")
-- end)
-- keymaps: swap
local swap = require("nvim-treesitter-textobjects.swap")
vim.keymap.set('n', ')a', function()
swap.swap_next('@parameter.inner')
end)
vim.keymap.set('n', '(a', function()
swap.swap_previous('@parameter.inner')
end)
-- keymaps: move
local move = require("nvim-treesitter-textobjects.move")
-- You can also pass a list to group multiple queries.
vim.keymap.set({ "n", "x", "o" }, "]o", function()
move.goto_next_start({ "@loop.inner", "@loop.outer" }, "textobjects")
end)
local ts_repeat_move = require "nvim-treesitter-textobjects.repeatable_move"
-- Repeat movement with ; and ,
-- ensure ; goes forward and , goes backward regardless of the last direction
-- vim.keymap.set({ "n", "x", "o" }, ";", ts_repeat_move.repeat_last_move_next)
-- vim.keymap.set({ "n", "x", "o" }, ",", ts_repeat_move.repeat_last_move_previous)
end
local function install_lspconfig()
-- ⭐ 如果你的neovim是透過source來生成,那麼所有內建的lua都會被放到 /usr/share/nvim/runtime/lua 目錄下,例如:
-- ~/neovim/runtime/lua/vim/lsp.lua # 假設你的neovim是clone到家目錄下,那麼此lsp.lua由source建立完成之後,就會被放到以下的目錄
-- /usr/share/nvim/runtime/lua/vim/lsp.lua # 而這些檔案正是nvim啟動時候會載入的檔案,如果你真想要debug,可以直接修改這些檔案來print出一些想要看到的資訊
-- local ok, m = pcall(require, "lspconfig") -- 👈 用neovim內建的lsp即可,頂多去參考nvim-lspconfig這插件的設定即可, 但不需要真的載入該插件
-- 🧙 ~/.local/state/nvim/lsp.log -- 在:checkhealth其實就可以看到log的路徑和目前log所佔的大小
-- :h vim.lsp.log_levels
-- vim.lsp.set_log_level("ERROR") -- 這樣可行,但我覺得用字串不太好
-- vim.lsp.set_log_level(vim.log.levels.OFF) -- 可以改用變數 -- 🧙 如果有需要可以自己加在my-customize.lua之中
-- 使用virtual_lines比virtualText或者是diagnostic.open_float的方式都好,所以不再需要這些指令
-- -- 新增切換虛擬文本診斷的命令
-- local diagnosticVirtualTextEnable = false
-- vim.api.nvim_create_user_command(
-- "ToggleDiagnosticVirtualText",
-- function(args)
-- if diagnosticVirtualTextEnable then
-- vim.diagnostic.config({
-- virtual_text = false
-- })
-- else
-- -- 診斷訊息顯示在行尾
-- vim.diagnostic.config({
-- virtual_text = {
-- prefix = '●', -- 前綴符號
-- suffix = '',
-- format = function(diagnostic)
-- -- print(vim.inspect(diagnostic))
-- return string.format([[
-- code: %s
-- source: %s
-- message: %s
-- ]],
-- diagnostic.code,
-- diagnostic.source,
-- diagnostic.message
-- )
-- end,
-- }
-- })
-- end
-- diagnosticVirtualTextEnable = not diagnosticVirtualTextEnable
-- if #args.fargs == 0 then
-- vim.notify("diagnosticVirtualTextEnable: " .. tostring(diagnosticVirtualTextEnable), vim.log.levels.INFO)
-- end
-- end,
-- {
-- nargs = "?",
-- desc = "切換診斷虛擬文本顯示"
-- }
-- )
-- vim.cmd("ToggleDiagnosticVirtualText --quite") -- 因為我的預設值設定為false,所以這樣相當改成預設會啟用
--
-- --- @type number|nil
-- local diagnosticHoverAutocmdId
-- vim.o.updatetime = 250
-- vim.api.nvim_create_user_command(
-- "ToggleDiagnosticHover",
-- function(args)
-- if diagnosticHoverAutocmdId then
-- -- 如果已經存在,則刪除特定的自動命令
-- vim.api.nvim_del_autocmd(diagnosticHoverAutocmdId)
-- diagnosticHoverAutocmdId = nil
-- else
-- -- 創建新的自動命令,並保存其ID
-- diagnosticHoverAutocmdId = vim.api.nvim_create_autocmd(
-- { "CursorHold", "CursorHoldI" }, {
-- callback = function()
-- vim.diagnostic.open_float(nil, { focus = false })
-- end
-- })
-- end
--
-- if #args.fargs == 0 then
-- vim.notify("DiagnosticHoverEnable: " .. tostring(diagnosticHoverAutocmdId ~= nil), vim.log.levels.INFO)
-- end
-- end,
-- {
-- nargs = "?",
-- desc = "切換診斷懸停顯示"
-- }
-- )
-- vim.cmd("ToggleDiagnosticHover --quite")
vim.diagnostic.config({
virtual_lines = {
current_line = true
},
-- virtual_text = false,
signs = {
text = {
[vim.diagnostic.severity.ERROR] = "",
[vim.diagnostic.severity.WARN] = "",
[vim.diagnostic.severity.INFO] = "", -- 💠 -- 例如: markdown中的連結不存在: Unresolved reference
[vim.diagnostic.severity.HINT] = "",
},
},
float = {
border = "rounded",
format = function(d) -- 用熱鍵 ]d 會顯示 :h ]d
return ("%s (%s) [%s]"):format(d.message, d.source, d.code or d.user_data.lsp.code)
end,
},
underline = true,
jump = {
float = true,
},
})
vim.api.nvim_create_user_command(
"SetDiagnostics",
function(args)
if args.fargs[1] == "1" then
vim.diagnostic.enable()
vim.notify("diagnostic enable", vim.log.levels.INFO)
elseif args.fargs[1] == "0" then
-- vim.diagnostic.disable() -- 已被棄用
vim.diagnostic.enable(false)
vim.notify("diagnostic disable", vim.log.levels.INFO)
end
end,
{
nargs = 1,
complete = function()
return { "1", "0" }
end,
desc = "set diagnostic"
}
)
vim.keymap.set("n", "gbh", function()
vim.lsp.buf.hover()
end,
{
desc = "💪 vim.lsp.buf.hover() 查看定義與使用方法 (可用<C-W><C-W>跳到出來的窗口)"
}
)
vim.api.nvim_create_user_command(
"LspBufDocSymbol",
function(args)
-- :lua vim.lsp.buf.document_symbol() -- 👈 可以如此,預設會直接寫到location list去
vim.lsp.buf.document_symbol({
on_list = function(result)
local target_kind = args.fargs[1] or "Function"
-- print(vim.inspect(result))
local symbols = result.items or {}
local list = {}
local cur_line = vim.fn.line(".")
local select_idx = 0
for i, symbol in ipairs(symbols) do -- i從1開始
if symbol.kind == target_kind then
if symbol.lnum <= cur_line then
select_idx = i
end
table.insert(list, {
filename = vim.api.nvim_buf_get_name(0),
lnum = symbol.lnum,
col = symbol.col,
text = symbol.text,
})
end
end
-- vim.fn.setqflist(list, 'r')
vim.fn.setloclist(0, list, 'r')
vim.cmd('lopen')
if select_idx > 0 then -- 不能是 :cc 0 只能是正整數
-- vim.cmd('cc ' .. select_idx) -- 可以不用copen也來cc
vim.cmd('ll ' .. select_idx) -- location list用ll qflist用cc
end
end
})
end,
{
desc = 'for item in vim.lsp.buf.document_symbol.items if item.kind == "Function"',
nargs = "?",
complete = function()
-- local kind_table = {}
vim.lsp.buf.document_symbol({
on_list = function(result) -- 這個不會傳到外層,獨立的一個session,變數不共用
local kind_table = {}
for _, symbol in ipairs(result.items) do
if kind_table[symbol.kind] == nil then
kind_table[symbol.kind] = true
end
end
local kinds = {}
for kind, _ in pairs(kind_table) do
table.insert(kinds, kind)
end
vim.w.cur_lsp_buf_document_symbol = table.concat(kinds, ",") -- 會有延遲到補全,但總比都沒有好
end
})
local cmp = {}
if vim.w.cur_lsp_buf_document_symbol then
cmp = vim.split(vim.w.cur_lsp_buf_document_symbol, ",")
end
return cmp
end
}
)
end
local function install_precognition()
-- 加載 precognition 插件
local ok, m = pcall(require, "precognition")
if not ok then
vim.notify("Failed to load precognition.nvim", vim.log.levels.ERROR)
return
end
-- 配置 precognition
m.setup({
-- 以下是 https://github.com/tris203/precognition.nvim/blob/531971e6d883e99b1572bf47294e22988d8fbec0/README.md?plain=1#L22-L46 的預設配置
startVisible = true,
showBlankVirtLine = true,
highlightColor = { link = "Comment" },
hints = {
Caret = { text = "^", prio = 2 },
Dollar = { text = "$", prio = 1 },
MatchingPair = { text = "%", prio = 5 },
Zero = { text = "0", prio = 1 },
w = { text = "w", prio = 10 },
b = { text = "b", prio = 9 },
e = { text = "e", prio = 8 },
W = { text = "W", prio = 7 },
B = { text = "B", prio = 6 },
E = { text = "E", prio = 5 },
},
gutterHints = {
G = { text = "G", prio = 10 },
gg = { text = "gg", prio = 9 },
PrevParagraph = { text = "{", prio = 8 },
NextParagraph = { text = "}", prio = 8 },
},
disabled_fts = {
"startify",
},
})
end
local function install_leap()
local ok, _ = pcall(require, "leap")
if not ok then
vim.notify("Failed to load leap", vim.log.levels.ERROR)
return
end
vim.go.ignorecase = true
require('leap').setup({
-- cd pack/motion/start/leap.nvim && git show f19d4359:lua/leap/main.lua | bat -l lua -P -r 79:83
case_sensitive = false, -- 第一鍵不區分大小寫, 第二個按鍵還是會分, 如果要第二鍵不分要讓vim.go.ignorecase為true
})
vim.keymap.set({ 'n', 'x', 'o' }, 's', '<Plug>(leap)')
vim.keymap.set('n', 'S', '<Plug>(leap-from-window)')
end
local function install_gitsigns()
local ok, plugin = pcall(require, "gitsigns")
if not ok then
vim.notify("Failed to load gitsigns", vim.log.levels.ERROR)
return
end
plugin.setup {
signs = {
add = { text = '┃' },
change = { text = '┃' },
delete = { text = '_' },
topdelete = { text = '‾' },
changedelete = { text = '~' },
untracked = { text = '┆' },
},
signs_staged = {
add = { text = '┃' },
change = { text = '┃' },
delete = { text = '_' },
topdelete = { text = '‾' },
changedelete = { text = '~' },
untracked = { text = '┆' },
},
signs_staged_enable = true,
signcolumn = true, -- Toggle with `:Gitsigns toggle_signs`
numhl = false, -- Toggle with `:Gitsigns toggle_numhl`
linehl = false, -- Toggle with `:Gitsigns toggle_linehl`
word_diff = false, -- Toggle with `:Gitsigns toggle_word_diff`
watch_gitdir = {
follow_files = true
},
auto_attach = true,
attach_to_untracked = false,
current_line_blame = false, -- Toggle with `:Gitsigns toggle_current_line_blame`
current_line_blame_opts = {
virt_text = true,
virt_text_pos = 'eol', -- 'eol' | 'overlay' | 'right_align'
delay = 1000,
ignore_whitespace = false,
virt_text_priority = 100,
use_focus = true,
},
current_line_blame_formatter = '<author>, <author_time:%R> - <summary>',
sign_priority = 6,
update_debounce = 100,
status_formatter = nil, -- Use default
max_file_length = 40000, -- Disable if file is longer than this (in lines)
preview_config = {
-- Options passed to nvim_open_win
border = 'single',
style = 'minimal',
relative = 'cursor',
row = 0,
col = 1
},
on_attach = function(bufnr)
local function map(mode, l, r, opts)
-- 簡化設定
opts = opts or {}
opts.buffer = bufnr
vim.keymap.set(mode, l, r, opts)
end
-- Navigation
map('n', ']c', function()
if vim.wo.diff then
-- 例如在: gitsigns.diffthis 的視窗開啟時 (<leader>hd)
vim.cmd.normal({ vim.v.count1 .. ']c', bang = true })
else
-- Warn: 用以下方式,有的跳轉是不對的
-- for _ = 1, vim.v.count1 do
-- plugin.nav_hunk('next')
-- end
plugin.nav_hunk('next', { count = vim.v.count1 })
end
end, { desc = '(git)往下找到異動處' })
map('n', '[c', function()
if vim.wo.diff then
vim.cmd.normal({ vim.v.count1 .. '[c', bang = true })
else
plugin.nav_hunk('prev', { count = vim.v.count1 })
end
end, { desc = '(git)往上找到個異動處' })
-- Actions
-- map('n', '<leader>hs', plugin.stage_hunk)
-- map('n', '<leader>hr', plugin.reset_hunk)
-- map('v', '<leader>hs', function() plugin.stage_hunk {vim.fn.line('.'), vim.fn.line('v')} end)
-- map('v', '<leader>hr', function() plugin.reset_hunk {vim.fn.line('.'), vim.fn.line('v')} end)
-- map('n', '<leader>hS', plugin.stage_buffer)
-- map('n', '<leader>hu', plugin.undo_stage_hunk)
-- map('n', '<leader>hR', plugin.reset_buffer)
-- map('n', '<leader>hn', plugin.next_hunk) -- 同等: plugin.nav_hunk('next')
map('n', '<leader>hp', plugin.preview_hunk,
{ desc = '(git)Hunk x of x 開啟preview(光標處必需有異動才能開啟), 查看目前光標處的異動, 開啟後常與prev, next使用. 此指令與diffthis很像,但是專注於一列' })
map('n', '<leader>hb', function()
plugin.blame_line { full = true }
end, { desc = '(git)blame 顯示光標處(不限於異動,所有都能)與最新一次commit時的差異' }
)
map('v', -- 由於<leader>t對我有用,所以為了避免影響已存在熱鍵的開啟效率,將此toogle設定在view下才可使用
'<leader>tb', plugin.toggle_current_line_blame,
{ desc = "(git)可以瞭解這一列最後commit的訊息和時間點 ex: You, 6 days, ago - my commit message. 如果不想要浪費效能,建議不用的時候就可以關掉(再下一次指令)" })
map('n', '<leader>hd', plugin.diffthis,
{ desc = '(git)查看當前文件的所有異動. 如果要看本次所有文件上的異動,可以使用:Telescope git_status' })
map('n', '<leader>hD', function()
plugin.diffthis('~')
end) -- 有包含上一次的提交修改
-- map('n', '<leader>td', plugin_gitsigns.toggle_deleted)
-- Text object
-- map({'o', 'x'}, 'ih', ':<C-U>Gitsigns select_hunk<CR>') -- 選取而已,作用不大
end
}
end
local function install_nvimWebDevicons()
local ok, m = pcall(require, "nvim-web-devicons") -- 只要這個插件有,不需要用require,nvim-tree就會自動導入,所以也不一定要寫這些配置
if not ok then
vim.notify("Failed to load nvim-web-devicons", vim.log.levels.ERROR)
return
end
m.setup {
-- 顏色不需要額外的項目就可以修改成功,但是icon要出現可能還需要額外的項目,例如: 使用github-nvim-theme後icon可以出現
-- https://github.com/projekt0n/github-nvim-theme
-- https://github.com/nvim-tree/nvim-web-devicons/blob/63f552a7f59badc6e6b6d22e603150f0d5abebb7/README.md?plain=1#L70-L125
override = {
zsh = {
icon = "",
color = "#428850",
cterm_color = "65",
name = "Zsh"
}
},
color_icons = true,
default = true,
strict = true,
variant = "light|dark",
override_by_filename = {
[".gitignore"] = {
icon = "",
color = "#f1502f",
name = "Gitignore"
},
["README.md"] = {
icon = "🧙",
color = "#00ff00",
name = "README"
}
},
override_by_extension = {
["log"] = {
icon = "",
color = "#ffff00",
name = "Log"
}
},
override_by_operating_system = {
["apple"] = {
icon = "",
color = "#A2AAAD",
cterm_color = "248",
name = "Apple",
},
},
}
-- set_default_icon(icon, color, cterm_color)
-- m.set_default_icon('😃', '#6d8086', 65)
end
local function install_nvim_tree()
local ok, m = pcall(require, "nvim-tree")
if not ok then
vim.notify("Failed to load nvim-tree", vim.log.levels.ERROR)
return
end
--[[
USAGE:
:NvimTreeOpen
g?
]] --
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1
-- optionally enable 24-bit colour
vim.opt.termguicolors = true
m.setup({
sort = {
sorter = "case_sensitive",
},
view = {
width = 30,
},
renderer = {
-- highlight_opened_files = "name", -- :help highlight_opened_files
group_empty = true,
-- :lua print("➜➜"") # 可以print這些試試,如果是亂碼,就是字型沒有提供,要安裝,並且改終端機的字型即可
icons = { -- (可選)
glyphs = {
default = "", -- 預設找不到項目的圖標
symlink = "",
git = {
unstaged = "",
staged = "S",
unmerged = "",
renamed = "➜",
deleted = "",
untracked = "U", -- 自定前綴,定成U表示這個項目還沒有被git添加
},
folder = { -- 這些是預設,如果不喜歡,也可以自己改成喜歡的emoji
default = "", -- 📁
open = "📂", --
empty = "",
empty_open = "",
symlink = "",
},
},
},
},
filters = {
dotfiles = true, -- 如果想要看到.開頭的檔案或目錄{.git/, .gitignore, .gitmodules, ...},要設定成false
},
})
-- vim.keymap.set("n", "<leader>t", ":NvimTreeOpen<CR>", { desc = "Open NvimTree" }) -- 可以先將TreeOpen到指定的位置,再用telescope去搜
vim.keymap.set("n", "<leader>t", ":NvimTreeToggle<CR>", { desc = "toggle NvimTree" })
local nvim_treeAPI = require "nvim-tree.api"
vim.keymap.set("n", "<A-t>", function()
local cur_file_path = vim.fn.expand("%:p")
-- 也可以考慮用 <C-W>T 把目前視窗「搬」到新 tab (原本視窗會消失)
vim.cmd("tabnew " .. cur_file_path) -- 會保留原本視窗,新 tab 顯示相同 buffer
end,
{ desc = "在新的頁籤開啟當前的文件" }
)
vim.api.nvim_create_user_command("CD",
function(args)
--- @type string
local path
if args.range == 0 then
if #args.args > 0 then
path = args.fargs[1]
else
path = vim.fn.system("git rev-parse --show-toplevel"):gsub("\n", "")
if vim.v.shell_error ~= 0 then
path = "~"
end
end
else
-- range
path = table.concat(utils.range.get_selected_text(), "")
end
-- NOTE: 在nvim-tree上做CD的路徑和當前編輯的是不同的工作路徑, 如果有需要可以在nvim-tree: gf 複製絕對路徑後使用CD切換
vim.cmd("cd " .. path)
nvim_treeAPI.tree.open({ path = path })
nvim_treeAPI.tree.change_root(path)
end,
{
nargs = "?", -- 預設為0,不接受參數, 1: 一個, *多個, ? 沒有或1個, + 一個或多個
desc = "更改工作目錄",
range = true,
}
)
end
local function install_telescope()
local ok, m = pcall(require, "telescope")
if not ok then
vim.notify("Failed to load telescope", vim.log.levels.ERROR)
return
end
-- 初始化 Telescope
-- vertical, horizontal. vertical有助於看到整個名稱(但是preview會被壓縮,不過因為我們定義了 <C-p> 為 toggle_preview所以用成horizontal要看清整個名稱也很方便)
local telescope_layout_strategy = "horizontal"
local telescope_file_ignore_patterns = {
"node_modules",
-- ".git/", -- agit, bgit這種也會匹配到
"%.git/", -- 這種是精確匹配. 因為 % 會轉譯,也就是.並非任一字元,而是真的匹配.
-- "^pack\\", -- 忽略pack目錄, 再打指令的時候用一個 \ 就好,此外不能用成 /
} -- 忽略文件或目錄模式
local actions = require "telescope.actions"
m.setup({
defaults = {
-- 預設配置
-- :lua print(vim.inspect(require('telescope.config').values.vimgrep_arguments))
vimgrep_arguments = {
"rg", -- man rg
"--color=never",
"--no-heading",
"--with-filename",
"--line-number",
"--column",
"--smart-case",
"--fixed-strings" -- 啟用精準匹配
},
prompt_prefix = "🔍 ", -- 搜索框前的圖標
selection_caret = " ", -- 選中時的指示符
entry_prefix = " ",
sorting_strategy = "ascending",
layout_strategy = telescope_layout_strategy,
layout_config = {
prompt_position = "top",
horizontal = {
preview_width = 0.6,
},
vertical = {
mirror = true, -- 翻轉,會影響提示輸入寬的位置, 為false時輸入在中間, preview在上
width = 0.8, -- 視窗寬度佔比
height = 0.9, -- 視窗高度佔比
preview_height = 0.5, -- 預覽區域佔整個視窗的比例
preview_cutoff = 0, -- 當結果數量少於此值時隱藏預覽, 設為0保證永遠顯示
},
},
file_ignore_patterns = telescope_file_ignore_patterns,
winblend = 0,
border = {},
borderchars = { "─", "│", "─", "│", "┌", "┐", "┘", "└" },
path_display = { "truncate" },
set_env = { ["COLORTERM"] = "truecolor" }, -- 修正配色
mappings = {
-- TIP: https://github.com/nvim-telescope/telescope.nvim/blob/b4da76be54691e854d3e0e02c36b0245f945c2c7/lua/telescope/mappings.lua#L133-L233
n = { -- 一般模式
["<C-p>"] = require('telescope.actions.layout').toggle_preview, -- 切換預覽
-- ["<leader>l"] = function(prompt_bufnr) -- 用<leader>也可以
-- local picker = require('telescope.actions.state').get_current_picker(prompt_bufnr) -- 這是mirror的toggle
-- picker.layout_strategy = "horizontal"
-- end
["K"] = actions.preview_scrolling_up,
["J"] = actions.preview_scrolling_down,
["H"] = actions.preview_scrolling_left,
["L"] = actions.preview_scrolling_right,
},
i = { -- 插入模式
["<C-k>"] = actions.preview_scrolling_up,
["<C-j>"] = actions.preview_scrolling_down,
["<C-h>"] = actions.preview_scrolling_left,
["<C-l>"] = actions.preview_scrolling_right,
["<C-p>"] = require('telescope.actions.layout').toggle_preview, -- 切換預覽
["<C-x>"] = function(
-- prompt_bufnr
)
local action_state = require("telescope.actions.state")
local entry = action_state.get_selected_entry()
if not entry then
return
end
local commit_sha = entry.value
-- vim.cmd("tabnew | r !git show " .. commit_sha)
-- 獲取 Git 根目錄
local git_root = vim.fn.system("git rev-parse --show-toplevel"):gsub("\n", "")
if vim.v.shell_error ~= 0 then
vim.notify("Not in a Git repository", vim.log.levels.ERROR)
return
end
-- 執行 git show --name-only 命令,獲取異動檔案列表
local files = vim.fn.systemlist("git show --name-only --pretty=format: " .. commit_sha)
-- 獲取 commit 提交訊息(第一行,通常是標題)
local commit_message = vim.fn.systemlist("git show --pretty=format:%s " .. commit_sha)[1] or
"No commit message"
-- 過濾空行並構建 quickfix list 條目
local qf_entries = {
{ text = string.format("[%s] %s", commit_sha, commit_message) },
{ text = 'term git show --name-only ' .. commit_sha },
{ text = 'term git show ' .. commit_sha .. " " .. "用i往下走到底可以看到完整內容" },
}
for _, file_relativepath in ipairs(files) do
if file_relativepath ~= "" then -- 忽略空行
local abs_path = git_root .. "/" .. file_relativepath
table.insert(qf_entries, {
-- filename = file_relativepath, -- 這個僅在git的目錄使用能找到, 如果路徑不在此,得到的清單路徑會是錯的
filename = abs_path, -- qflist的路徑(filename)如果是對的,就會自動依據當前的工作目錄去變化
lnum = 1,
-- text = "File changed in commit " .. commit_sha
})
end
end
-- 將結果寫入 quickfix list
if #qf_entries > 0 then
vim.fn.setqflist(qf_entries)
vim.cmd("copen") -- 自動打開 quickfix list 視窗
-- require("telescope.actions").close(prompt_bufnr) -- 關閉 Telescope 視窗, 已經關閉了,不需要再關,不然反而會錯
else
vim.notify("No files changed in this commit", vim.log.levels.WARN)
end