Initial commit

This commit is contained in:
Hoang Nguyen 2023-10-28 00:00:00 +07:00
commit 294e135ed7
Signed by: folliehiyuki
GPG Key ID: B0567C20730E9B11
103 changed files with 7040 additions and 0 deletions

15
.neoconf.json Normal file
View File

@ -0,0 +1,15 @@
{
"neoconf": {
"live_reload": false,
"import": {
"vscode": false
}
},
"lspconfig": {
"gopls": {
"gopls.buildFlags": [
"-tags=mage"
]
}
}
}

6
.stylua.toml Normal file
View File

@ -0,0 +1,6 @@
column_width = 120
line_endings = 'Unix'
indent_type = 'Spaces'
indent_width = 4
quote_style = 'AutoPreferSingle'
call_parentheses = 'NoSingleTable'

9
LICENSE Normal file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2021-2023 Hoang Nguyen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

62
README.md Normal file
View File

@ -0,0 +1,62 @@
# FollieHiyuki's Neovim configuration
This Neovim config used to live within [my dotfiles](/FollieHiyuki/dotfiles-ansible). Due to the complexity of refactoring both regular files/templates and this Lua codebase, I decided to move it into its own repository. As such, this project stays under the same license as my dotfiles, MIT.
## TODO
### Colorschemes
- OneDark
- Catpuccin
### Missing tree-sitter parsers
- [templ](https://github.com/vrischmann/tree-sitter-templ)
- [rescript](https://github.com/nkrkv/tree-sitter-rescript/)
- nftables
- Go template (text/html)
- Jinja2
- [typst](https://github.com/typst/typst/issues/118)
### Additional DAP/LSP servers
- elixirls (config for `nvim-lspconfig` and `nvim-dap` + install script)
- denols
- ocamllsp
- vscode-js-debug (config for `nvim-dap` + install script)
### More plugins
- clangd_extensions.nvim
- crates.nvim
- numb.nvim
- package-info.nvim
- pretty-fold.nvim / nvim-ufo
- refactoring.nvim
- rust-tools.nvim
- telekasten.nvim
- tangerine.nvim / aniseed / hotpot / nfnl
- silicon.nvim / silicon.lua
- nabla.nvim
- markdown-preview.nvim -> peek.nvim / smp.nvim
- grpc-nvim
- nvim-ide
- haskell-tools.nvim
- nvim-asciidoc-preview
- lsp-lens.nvim
- venv-selector.nvim
- virtual-types.nvim
- hover.nvim
- nvim-tree.lua -> neo-tree???
### Logic
- Smooth colorschemes changing (dynamic highlight groups registration via event hooks)
## FAQ
### Why not using [mason.nvim](https://github.com/williamboman/mason.nvim)?
Most things installed via **mason.nvim** are in binary format, which might be incompatible to run on the Linux distribution I use - [AlpineLinux](https://alpinelinux.org). I resolved to custom [mage](https://magefile.org) tasks instead. The [tasks' source code](./magefile.go) is pretty simple and naive, but it works for me.
External LSP servers that can't be installed directly from AlpineLinux's repositories, or with simple `cargo/go install` commands, are defined inside [pkg.yaml](./pkg.yaml) file.

View File

@ -0,0 +1,4 @@
local o = vim.opt_local
o.wrap = true
o.number = false
o.relativenumber = false

1
after/ftplugin/gemini.lua Symbolic link
View File

@ -0,0 +1 @@
asciidoc.lua

5
after/ftplugin/go.lua Normal file
View File

@ -0,0 +1,5 @@
local o = vim.opt_local
o.list = false
o.softtabstop = 2
o.tabstop = 2
o.expandtab = false

1
after/ftplugin/gomod.lua Symbolic link
View File

@ -0,0 +1 @@
go.lua

1
after/ftplugin/gowork.lua Symbolic link
View File

@ -0,0 +1 @@
/home/follie/.config/nvim/after/ftplugin/go.lua

6
after/ftplugin/hcl.lua Normal file
View File

@ -0,0 +1,6 @@
local o = vim.opt_local
o.autoindent = false
o.expandtab = true
o.softtabstop = 2
o.tabstop = 2
o.commentstring = "# %s"

9
after/ftplugin/json.lua Normal file
View File

@ -0,0 +1,9 @@
local o = vim.opt_local
o.autoindent = true
o.conceallevel = 0
o.expandtab = true
o.foldmethod = 'syntax'
o.formatoptions = 'tcq2l'
o.shiftwidth = 2
o.softtabstop = 2
o.tabstop = 4

1
after/ftplugin/jsonc.lua Symbolic link
View File

@ -0,0 +1 @@
json.lua

4
after/ftplugin/make.lua Normal file
View File

@ -0,0 +1,4 @@
local o = vim.opt_local
o.expandtab = false
o.softtabstop = 2
o.tabstop = 2

1
after/ftplugin/markdown.lua Symbolic link
View File

@ -0,0 +1 @@
/home/follie/.config/nvim/after/ftplugin/asciidoc.lua

View File

@ -0,0 +1 @@
hcl.lua

12
after/ftplugin/tex.lua Normal file
View File

@ -0,0 +1,12 @@
local o = vim.opt_local
o.wrap = true
o.number = false
o.relativenumber = false
-- Preview file at cursor with TexLab LSP command
vim.keymap.set('n', '<localleader>p', '<cmd>TexlabForward<CR>', {
buffer = true,
noremap = true,
silent = true,
desc = 'Preview LaTEX file',
})

4
after/ftplugin/vim.lua Normal file
View File

@ -0,0 +1,4 @@
local o = vim.opt_local
o.colorcolumn = { 120 }
o.iskeyword = vim.opt.iskeyword + ':' + '#'
o.tags = vim.opt.tags + '$DATA_PATH/tags'

6
after/ftplugin/yaml.lua Normal file
View File

@ -0,0 +1,6 @@
local o = vim.opt_local
o.autoindent = true
o.expandtab = true
o.softtabstop = 2
o.tabstop = 2
o.indentkeys:remove(':')

1
after/plugin/colors.lua Normal file
View File

@ -0,0 +1 @@
vim.cmd('colorscheme nord')

View File

@ -0,0 +1,17 @@
if exists("b:current_syntax")
finish
endif
if !exists("g:main_syntax")
let g:main_syntax = 'html'
endif
runtime! syntax/gotexttmpl.vim
runtime! syntax/html.vim
unlet b:current_syntax
syn cluster htmlPreproc add=gotplAction,goTplComment
let b:current_syntax = "gohtmltmpl"
" vim: sw=2 ts=2 et

View File

@ -0,0 +1,83 @@
" Copyright 2011 The Go Authors. All rights reserved.
" Use of this source code is governed by a BSD-style
" license that can be found in the LICENSE file.
"
" gotexttmpl.vim: Vim syntax file for Go templates.
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
finish
endif
syn case match
" Go escapes
syn match goEscapeOctal display contained "\\[0-7]\{3}"
syn match goEscapeC display contained +\\[abfnrtv\\'"]+
syn match goEscapeX display contained "\\x\x\{2}"
syn match goEscapeU display contained "\\u\x\{4}"
syn match goEscapeBigU display contained "\\U\x\{8}"
syn match goEscapeError display contained +\\[^0-7xuUabfnrtv\\'"]+
hi def link goEscapeOctal goSpecialString
hi def link goEscapeC goSpecialString
hi def link goEscapeX goSpecialString
hi def link goEscapeU goSpecialString
hi def link goEscapeBigU goSpecialString
hi def link goSpecialString Special
hi def link goEscapeError Error
" Strings and their contents
syn cluster goStringGroup contains=goEscapeOctal,goEscapeC,goEscapeX,goEscapeU,goEscapeBigU,goEscapeError
syn region goString contained start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@goStringGroup
syn region goRawString contained start=+`+ end=+`+
hi def link goString String
hi def link goRawString String
" Characters; their contents
syn cluster goCharacterGroup contains=goEscapeOctal,goEscapeC,goEscapeX,goEscapeU,goEscapeBigU
syn region goCharacter contained start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=@goCharacterGroup
hi def link goCharacter Character
" Integers
syn match goDecimalInt contained "\<\d\+\([Ee]\d\+\)\?\>"
syn match goHexadecimalInt contained "\<0x\x\+\>"
syn match goOctalInt contained "\<0\o\+\>"
syn match goOctalError contained "\<0\o*[89]\d*\>"
syn cluster goInt contains=goDecimalInt,goHexadecimalInt,goOctalInt
" Floating point
syn match goFloat contained "\<\d\+\.\d*\([Ee][-+]\d\+\)\?\>"
syn match goFloat contained "\<\.\d\+\([Ee][-+]\d\+\)\?\>"
syn match goFloat contained "\<\d\+[Ee][-+]\d\+\>"
" Imaginary literals
syn match goImaginary contained "\<\d\+i\>"
syn match goImaginary contained "\<\d\+\.\d*\([Ee][-+]\d\+\)\?i\>"
syn match goImaginary contained "\<\.\d\+\([Ee][-+]\d\+\)\?i\>"
syn match goImaginary contained "\<\d\+[Ee][-+]\d\+i\>"
hi def link goInt Number
hi def link goFloat Number
hi def link goImaginary Number
" Token groups
syn cluster gotplLiteral contains=goString,goRawString,goCharacter,@goInt,goFloat,goImaginary
syn keyword gotplControl contained if else end range with template
syn keyword gotplFunctions contained and html index js len not or print printf println urlquery eq ne lt le gt ge
syn match gotplVariable contained /\$[a-zA-Z0-9_]*\>/
syn match goTplIdentifier contained /\.[^[:blank:]}]\+\>/
hi def link gotplControl Keyword
hi def link gotplFunctions Function
hi def link goTplVariable Special
syn region gotplAction start="{{" end="}}" contains=@gotplLiteral,gotplControl,gotplFunctions,gotplVariable,goTplIdentifier display
syn region goTplComment start="{{\(- \)\?/\*" end="\*/\( -\)\?}}" display
hi def link gotplAction PreProc
hi def link goTplComment Comment
let b:current_syntax = "gotexttmpl"
" vim: sw=2 ts=2 et

90
after/syntax/jinja.vim Normal file
View File

@ -0,0 +1,90 @@
" Oringinal author: Armin Ronacher <armin.ronacher@active-4.com>
" Modified by: Alejandro "HiPhish" Sanchez
" See the LICENSE file for copyright information
syntax case match
if exists('b:current_syntax') && b:current_syntax =~? 'jinja'
finish
endif
" Jinja template built-in tags and parameters (without filter, macro, is and raw, they
" have special threatment)
syn keyword jinjaStatement containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained and if else in not or recursive as import
syn keyword jinjaStatement containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained is filter skipwhite nextgroup=jinjaFilter
syn keyword jinjaStatement containedin=jinjaTagBlock contained macro skipwhite nextgroup=jinjaFunction
syn keyword jinjaStatement containedin=jinjaTagBlock contained block skipwhite nextgroup=jinjaBlockName
" Variable Names
syn match jinjaVariable containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[a-zA-Z_][a-zA-Z0-9_]*/
syn keyword jinjaSpecial containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained false true none False True None loop super caller varargs kwargs
" Filters
syn match jinjaOperator "|" containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained skipwhite nextgroup=jinjaFilter
syn match jinjaFilter contained /[a-zA-Z_][a-zA-Z0-9_]*/
syn match jinjaFunction contained /[a-zA-Z_][a-zA-Z0-9_]*/
syn match jinjaBlockName contained /[a-zA-Z_][a-zA-Z0-9_]*/
" Jinja template constants
syn region jinjaString containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained start=/"/ skip=/\(\\\)\@<!\(\(\\\\\)\@>\)*\\"/ end=/"/
syn region jinjaString containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained start=/'/ skip=/\(\\\)\@<!\(\(\\\\\)\@>\)*\\'/ end=/'/
syn match jinjaNumber containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[0-9]\+\(\.[0-9]\+\)\?/
" Operators
syn match jinjaOperator containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[+\-*\/<>=!,:]/
syn match jinjaPunctuation containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /[()\[\]]/
syn match jinjaOperator containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained /\./ nextgroup=jinjaAttribute
syn match jinjaAttribute contained /[a-zA-Z_][a-zA-Z0-9_]*/
" Jinja template tag and variable blocks
syn region jinjaNested matchgroup=jinjaOperator start="(" end=")" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained
syn region jinjaNested matchgroup=jinjaOperator start="\[" end="\]" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained
syn region jinjaNested matchgroup=jinjaOperator start="{" end="}" transparent display containedin=jinjaVarBlock,jinjaTagBlock,jinjaNested contained
syn region jinjaTagBlock matchgroup=jinjaTagDelim start=/{%-\?/ end=/-\?%}/ containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaRaw,jinjaString,jinjaNested,jinjaComment
syn region jinjaVarBlock matchgroup=jinjaVarDelim start=/{{-\?/ end=/-\?}}/ containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaRaw,jinjaString,jinjaNested,jinjaComment
" Jinja template 'raw' tag
syn region jinjaRaw matchgroup=jinjaRawDelim start="{%\s*raw\s*%}" end="{%\s*endraw\s*%}" containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaString,jinjaComment
" Jinja comments
syn region jinjaComment matchgroup=jinjaCommentDelim start="{#" end="#}" containedin=ALLBUT,jinjaTagBlock,jinjaVarBlock,jinjaString
" Block start keywords. A bit tricker. We only highlight at the start of a
" tag block and only if the name is not followed by a comma or equals sign
" which usually means that we have to deal with an assignment.
syn match jinjaStatement containedin=jinjaTagBlock contained /\({%-\?\s*\)\@<=\<[a-zA-Z_][a-zA-Z0-9_]*\>\(\s*[,=]\)\@!/
" and context modifiers
syn match jinjaStatement containedin=jinjaTagBlock contained /\<with\(out\)\?\s\+context\>/
command -nargs=+ HiLink hi def link <args>
HiLink jinjaPunctuation jinjaOperator
HiLink jinjaAttribute jinjaVariable
HiLink jinjaFunction jinjaFilter
HiLink jinjaTagDelim jinjaTagBlock
HiLink jinjaVarDelim jinjaVarBlock
HiLink jinjaCommentDelim jinjaComment
HiLink jinjaRawDelim jinja
HiLink jinjaSpecial Special
HiLink jinjaOperator Normal
HiLink jinjaRaw Normal
HiLink jinjaTagBlock PreProc
HiLink jinjaVarBlock PreProc
HiLink jinjaStatement Statement
HiLink jinjaFilter Function
HiLink jinjaBlockName Function
HiLink jinjaVariable Identifier
HiLink jinjaString Constant
HiLink jinjaNumber Constant
HiLink jinjaComment Comment
delcommand HiLink
let b:current_syntax = 'jinja'

40
after/syntax/nftables.vim Normal file
View File

@ -0,0 +1,40 @@
" Source: https://github.com/nfnty/vim-nftables
" License: MIT
if exists('b:current_syntax')
finish
endif
syn match nftablesSet /{.*}/ contains=nftablesSetEntry
syn match nftablesSetEntry /[a-zA-Z0-9]\+/ contained
hi def link nftablesSet Keyword
hi def link nftablesSetEntry Operator
syn match nftablesNumber "\<[0-9A-Fa-f./:]\+\>" contains=nftablesMask,nftablesDelimiter
syn match nftablesHex "\<0x[0-9A-Fa-f]\+\>"
syn match nftablesDelimiter "[./:]" contained
syn match nftablesMask "/[0-9.]\+" contained contains=nftablesDelimiter
hi def link nftablesNumber Number
hi def link nftablesHex Number
hi def link nftablesDelimiter Operator
hi def link nftablesMask Operator
syn region Comment start=/#/ end=/$/
syn region String start=/"/ end=/"/
syn keyword Function flush
syn keyword Function table chain map
syn keyword Statement type hook
syn keyword Type ip ip6 inet arp bridge
syn keyword Type filter nat route
syn keyword Type ether vlan arp ip icmp igmp ip6 icmpv6 tcp udp udplite sctp dccp ah esp comp icmpx
syn keyword Type ct
syn keyword Type length protocol priority mark iif iifname iiftype oif oifname oiftype skuid skgid rtclassid
syn keyword Constant prerouting input forward output postrouting
syn keyword Special snat dnat masquerade redirect
syn keyword Special accept drop reject queue
syn keyword Keyword continue return jump goto
syn keyword Keyword counter log limit
syn keyword Keyword define
let b:current_syntax = 'nftables'

122
after/syntax/rescript.vim Normal file
View File

@ -0,0 +1,122 @@
if exists("b:current_syntax")
finish
endif
" See https://github.com/rescript-lang/vim-rescript/issues/14
syntax sync minlines=600
" Boolean
syntax keyword resBoolean true false
" Keywords
syntax keyword resKeyword let rec type external mutable lazy private of with
syntax keyword resKeyword if else switch when
syntax keyword resKeyword and as open include module in constraint import export
syntax keyword resKeyword for to downto while
syntax keyword resKeyword try catch exception assert
syntax keyword resKeyword async await
" Types
syntax keyword resType bool int float char string unit
syntax keyword resType list array option ref exn format
" Operators
syntax keyword resOperator mod land lor lxor lsl lsr asr
syntax keyword resOperator or
syntax match resOperator "\v\="
syntax match resOperator "\v\*"
syntax match resOperator "\v/"
syntax match resOperator "\v\+"
syntax match resOperator "\v-"
syntax match resOperator "\v\*\."
syntax match resOperator "\v/\."
syntax match resOperator "\v\+\."
syntax match resOperator "\v-\."
syntax match resOperator "\v\<"
syntax match resOperator "\v\<\="
syntax match resOperator "\v\>"
syntax match resOperator "\v\>\="
syntax match resOperator "\v\@"
syntax match resOperator "\v\!"
syntax match resOperator "\v\|"
syntax match resOperator "\v\&"
" Refs
syntax match resOperator "\v\:\="
" Arrows / Pipes
syntax match resArrowPipe "\v\=\>"
syntax match resArrowPipe "\v\-\>"
syntax match resArrowPipe "\v\|\>"
syntax match resArrowPipe "\v\@\@"
" Comment
syntax region resSingleLineComment start="//" end="$" contains=resTodo,@Spell
syntax region resMultiLineComment start="/\*\s*" end="\*/" contains=@Spell,resTodo,resMultiLineComment
syntax keyword resTodo contained TODO FIXME XXX NOTE
" Char
syntax match resChar "\v'\\.'|'.'"
syntax match resNumber "-\=\<\d\(_\|\d\)*[l|L|n]\?\>"
syntax match resNumber "-\=\<0[x|X]\(\x\|_\)\+[l|L|n]\?\>"
syntax match resNumber "-\=\<0[o|O]\(\o\|_\)\+[l|L|n]\?\>"
syntax match resNumber "-\=\<0[b|B]\([01]\|_\)\+[l|L|n]\?\>"
syntax match resFloat "-\=\<\d\(_\|\d\)*\.\?\(_\|\d\)*\([eE][-+]\=\d\(_\|\d\)*\)\=\>"
" Module / Constructor
syntax match resModuleOrVariant "\v<[A-Z][A-Za-z0-9_'$]*"
syntax match resModuleChain "\v<[A-Z][A-Za-z0-9_'$]*\."
" Attribute
syntax match resAttribute "\v\@([a-zA-z][A-Za-z0-9_']*)(\.([a-zA-z])[A-Za-z0-9_']*)*"
" String
syntax match resUnicodeChar "\v\\u[A-Fa-f0-9]\{4}" contained
syntax match resStringEscapeSeq "\v\\[\\"ntbrf]" contained
syntax match resInterpolatedStringEscapeSeq "\v\\[\\`ntbrf]" contained
syntax region resString start="\v\"" end="\v\"" contains=resStringEscapeSeq,resUnicodeChar
" Interpolation
syntax match resInterpolationVariable "\v\$[a-z_][A-Za-z0-0_'$]*" contained
syntax region resInterpolationBlock matchgroup=resInterpolationDelimiters start="\v\$\{" end="\v\}" contained contains=TOP
syntax region resString start="\v`" end="\v`" contains=resInterpolationBlock,resInterpolatedStringEscapeSeq
syntax region resString start="\v[a-z]`" end="\v`" contains=resInterpolationBlock,resInterpolationVariable,resInterpolatedStringEscapeSeq
" Polymorphic variants
syntax match resPolyVariant "\v#[A-za-z][A-Za-z0-9_'$]*"
syntax match resPolyVariant "\v#[0-9]+"
syntax match resPolyVariant "\v#\".*\""
syntax match resPolyVariant "\v#\\\".*\""
highlight default link resBoolean Boolean
highlight default link resKeyword Keyword
highlight default link resType Type
highlight default link resOperator Operator
highlight default link resArrowPipe Operator
highlight default link resSingleLineComment Comment
highlight default link resMultiLineComment Comment
highlight default link resTodo TODO
highlight default link resChar Character
highlight default link resNumber Number
highlight default link resFloat Float
highlight default link resModuleOrVariant Function
highlight default link resPolyVariant Function
highlight default link resModuleChain Macro
highlight default link resUnicodeChar Character
highlight default link resStringEscapeSeq Character
highlight default link resInterpolatedStringEscapeSeq Character
highlight default link resString String
highlight default link resInterpolationDelimiters Macro
highlight default link resInterpolationVariable Macro
highlight default link resAttribute PreProc
let b:current_syntax = "rescript"

56
after/syntax/templ.vim Normal file
View File

@ -0,0 +1,56 @@
" Vim syntax file
" Language: templ
" syn region templCss start=/{% css .* %}/ keepend end=/{% endcss %}/ contains=cssTagName,cssAttributeSelector,cssClassName,cssIdentifier,cssAtRule,cssAttrRegion,css.*Prop,cssComment,cssValue.*,cssColor,cssURL,cssImportant,cssCustomProp,cssError,cssStringQ,cssStringQQ,cssFunction,cssUnicodeEscape,cssVendor,cssDefinition,cssHacks,cssNoise
if version < 600
syn clear
elseif exists("b:current_syntax")
finish
endif
if !exists("main_syntax")
let main_syntax = 'templ'
endif
syn include @html syntax/html.vim
unlet b:current_syntax
syn include @css syntax/css.vim
unlet b:current_syntax
syn include @go syntax/go.vim
unlet b:current_syntax
runtime! syntax/go.vim
unlet b:current_syntax
" templ
syn match templTemplateDec /^templ/ nextgroup=templReceiverDecl,templFunction skipwhite skipnl
syn match templReceiverDecl /(\s*\zs\%(\%(\w\+\s\+\)\?\*\?\w\+\%(\[\%(\%(\[\]\)\?\w\+\%(,\s*\)\?\)\+\]\)\?\)\ze\s*)/ contained contains=goReceiverVar,goReceiverType,goPointerOperator nextgroup=templFunction skipwhite skipnl
syn match templFunction /\w\+/ nextgroup=templSimpleParams,templTypeParams contained skipwhite skipnl
syn match templSimpleParams /(\%(\w\|\_s\|[*\.\[\],\{\}<>-]\)*)/ contained contains=goParamName,goType nextgroup=templTemplateBlock skipwhite skipnl
syn match templTypeParams /\[\%(\w\+\s\+\%(\~\?\%(\[]\)\?\w\%(\w\||\)\)*\%(,\s*\)\?\)\+\]/ nextgroup=templSimpleParams contained skipwhite skipnl
syn region templTemplateBlock start="{" end="}" contains=@html,templCall,@templFlows,templTemplateBlock contained skipwhite skipnl
" @template()
syn match templCall /@/ nextgroup=templFunction contained skipwhite skipnl
" for ...
syn cluster templFlows contains=templFlow,templSwitch
syn match templFlow /\(for\|if\)/ contained skipwhite skipnl nextgroup=templFlowBlock
syn match templSwitch /switch/ contained skipwhite skipnl nextgroup=templSwitchBlock
syn keyword templSwitchKeyword case contained
syn keyword templSwitchKeyword default contained
syn region templSwitchBlock start=/.*{/ end="}" contained skipwhite skipnl contains=@html,templCall,@templFlows,templSwitchKeyword
syn region templFlowBlock start=/.*{/ end="}" contained skipwhite skipnl contains=@html,templCall,@templFlows
hi def link templTemplateDec Keyword
hi def link templFlow Keyword
hi def link templSwitch Keyword
hi def link templSwitchKeyword Keyword
hi def link templCall Special
let b:current_syntax = "templ"

407
after/syntax/typst.vim Normal file
View File

@ -0,0 +1,407 @@
" Vim syntax file
" Language: Typst
" Maintainer: Kaj Munhoz Arfvidsson
" Latest Revision: Apr 2023
if exists("b:current_syntax")
finish
endif
syntax sync fromstart
syntax spell toplevel
" Common {{{1
syntax cluster typstCommon
\ contains=@typstComment
" Common > Comment {{{2
syntax cluster typstComment
\ contains=typstCommentBlock,typstCommentLine
syntax match typstCommentBlock
\ #/\*\%(\_.\{-}\)\*/#
\ contains=typstCommentTodo,@Spell
syntax match typstCommentLine
\ #//.*#
\ contains=typstCommentTodo,@Spell
syntax keyword typstCommentTodo
\ contained
\ TODO FIXME XXX TBD
" Code {{{1
syntax cluster typstCode
\ contains=@typstCommon
\ ,@typstCodeKeywords
\ ,@typstCodeConstants
\ ,@typstCodeIdentifiers
\ ,@typstCodeFunctions
\ ,@typstCodeParens
" Code > Keywords {{{2
syntax cluster typstCodeKeywords
\ contains=typstCodeConditional
\ ,typstCodeRepeat
\ ,typstCodeKeyword
\ ,typstCodeStatement
syntax keyword typstCodeConditional
\ contained
\ if else
syntax keyword typstCodeRepeat
\ contained
\ while for
syntax keyword typstCodeKeyword
\ contained
\ not in and or return
syntax region typstCodeStatement
\ contained
\ matchgroup=typstCodeStatementWord start=/\v(let|set|show|import|include)>-@!/ end=/\v%(;|$)/
\ contains=@typstCode
" Code > Identifiers- {{{2
syntax cluster typstCodeIdentifiers
\ contains=typstCodeIdentifier
\ ,typstCodeFieldAccess
syntax match typstCodeIdentifier
\ contained
\ /\v\K\k*%(-+\k+)*>-@!(<%(let|set|show|import|include))@<![\.\[\(]@!/
syntax match typstCodeFieldAccess
\ contained
\ /\v\K\k*%(-+\k+)*>-@!(<%(let|set|show|import|include))@<!\.[\[\(]@!/
\ nextgroup=typstCodeFieldAccess,typstCodeFunction
" Code > Functions {{{2
syntax cluster typstCodeFunctions
\ contains=typstCodeFunction
syntax match typstCodeFunction
\ contained
\ /\v\K\k*%(-+\k+)*[\(\[]@=/
\ nextgroup=typstCodeFunctionArgument
syntax match typstCodeFunctionArgument
\ contained
\ /\v%(%(\(.{-}\)|\[.{-}\]|\{.{-}\}))*/ transparent
\ contains=@typstCode
" Code > Constants {{{2
syntax cluster typstCodeConstants
\ contains=typstCodeConstant
\ ,typstCodeNumberInteger
\ ,typstCodeNumberFloat
\ ,typstCodeNumberLength
\ ,typstCodeNumberAngle
\ ,typstCodeNumberRatio
\ ,typstCodeNumberFraction
\ ,typstCodeString
syntax match typstCodeConstant
\ contained
\ /\v<%(none|auto|true|false)-@!>/
syntax match typstCodeNumberInteger
\ contained
\ /\v<\d+>/
syntax match typstCodeNumberFloat
\ contained
\ /\v<\d+\.\d*>/
syntax match typstCodeNumberLength
\ contained
\ /\v<\d+(\.\d*)?(pt|mm|cm|in|em)>/
syntax match typstCodeNumberAngle
\ contained
\ /\v<\d+(\.\d*)?(deg|rad)>/
syntax match typstCodeNumberRatio
\ contained
\ /\v<\d+(\.\d*)?\%/
syntax match typstCodeNumberFraction
\ contained
\ /\v<\d+(\.\d*)?fr>/
syntax region typstCodeString
\ contained
\ start=/"/ skip=/\v\\\\|\\"/ end=/"/
\ contains=@Spell
" Code > Parens {{{2
syntax cluster typstCodeParens
\ contains=typstCodeParen
\ ,typstCodeBrace
\ ,typstCodeBracket
\ ,typstCodeDollar
\ ,typstMarkupRawInline
\ ,typstMarkupRawBlock
syntax region typstCodeParen
\ contained
\ matchgroup=Noise start=/\v\(/ end=/\v\)/
\ contains=@typstCode
syntax region typstCodeBrace
\ contained
\ matchgroup=Noise start=/\v\{/ end=/\v\}/
\ contains=@typstCode
syntax region typstCodeBracket
\ contained
\ matchgroup=Noise start=/\v\[/ end=/\v\]/
\ contains=@typstMarkup
syntax region typstCodeDollar
\ contained
\ matchgroup=Number start=/\v\$/ end=/\v\$/
\ contains=@typstMath
" Hashtag {{{1
syntax cluster typstHashtag
\ contains=@typstHashtagKeywords
\ ,@typstHashtagConstants
\ ,@typstHashtagIdentifiers
\ ,@typstHashtagFunctions
\ ,@typstHashtagParens
" Hashtag > Keywords {{{2
syntax cluster typstHashtagKeywords
\ contains=typstHashtagConditional
\ ,typstHashtagRepeat
\ ,typstHashtagKeywords
\ ,typstHashtagStatement
syntax match typstHashtagControlFlowError
\ /\v#%(if|while|for)>-@!.{-}$\_.{-}%(\{|\[)/
syntax match typstHashtagControlFlow
\ /\v#%(if|while|for)>-@!.{-}\ze%(\{|\[)/
\ contains=typstHashtagConditional,typstHashtagRepeat
\ nextgroup=@typstCode
syntax region typstHashtagConditional
\ contained
\ start=/\v#if>-@!/ end=/\v\ze(\{|\[)/
\ contains=@typstCode
syntax region typstHashtagRepeat
\ contained
\ start=/\v#(while|for)>-@!/ end=/\v\ze(\{|\[)/
\ contains=@typstCode
syntax match typstHashtagKeyword
\ /\v#(return)>-@!/
\ skipwhite nextgroup=@typstCode
syntax region typstHashtagStatement
\ matchgroup=typstHashtagStatementWord start=/\v#(let|set|show|import|include)>-@!/ end=/\v%(;|$)/
\ contains=@typstCode
" Hashtag > Constants {{{2
syntax cluster typstHashtagConstants
\ contains=typstHashtagConstant
syntax match typstHashtagConstant
\ /\v#(none|auto|true|false)>-@!/
" Hashtag > Identifiers {{{2
syntax cluster typstHashtagIdentifiers
\ contains=typstHashtagIdentifier
\ ,typstHashtagFieldAccess
syntax match typstHashtagIdentifier
\ /\v#\K\k*%(-+\k+)*>-@!(<%(let|set|show|import|include|if|while|for|return))@<![\.\[\(]@!/
syntax match typstHashtagFieldAccess
\ /\v#\K\k*%(-+\k+)*>-@!(<%(let|set|show|import|include|if|while|for|return))@<!\.[\[\(]@!/
\ nextgroup=typstCodeFieldAccess,typstCodeFunction
" Hashtag > Functions {{{2
syntax cluster typstHashtagFunctions
\ contains=typstHashtagFunction
syntax match typstHashtagFunction
\ /\v#\K\k*%(-+\k+)*[\(\[]@=/
\ nextgroup=typstCodeFunctionArgument
" Hashtag > Parens {{{2
syntax cluster typstHashtagParens
\ contains=typstHashtagParen
\ ,typstHashtagBrace
\ ,typstHashtagBracket
\ ,typstHashtagDollar
syntax region typstHashtagParen
\ matchgroup=Noise start=/\v\#\(/ end=/\v\)/
\ contains=@typstCode
syntax region typstHashtagBrace
\ matchgroup=Noise start=/\v\#\{/ end=/\v\}/
\ contains=@typstCode
syntax region typstHashtagBracket
\ matchgroup=Noise start=/\v\#\[/ end=/\v\]/
\ contains=@typstMarkup
syntax region typstHashtagDollar
\ matchgroup=Noise start=/\v\#\$/ end=/\v\$/
\ contains=@typstMath
" Markup {{{1
syntax cluster typstMarkup
\ contains=@typstCommon
\ ,@Spell
\ ,@typstHashtag
\ ,@typstMarkupText
\ ,@typstMarkupParens
" Markup > Text {{{2
syntax cluster typstMarkupText
\ contains=typstMarkupRawInline
\ ,typstMarkupRawBlock
\ ,typstMarkupLabel
\ ,typstMarkupReference
\ ,typstMarkupUrl
\ ,typstMarkupHeading
\ ,typstMarkupBulletList
\ ,typstMarkupEnumList
\ ,typstMarkupBold
\ ,typstMarkupItalic
\ ,typstMarkupLinebreak
\ ,typstMarkupNonbreakingSpace
\ ,typstMarkupShy
\ ,typstMarkupDash
\ ,typstMarkupEllipsis
\ ,typstMarkupTermList
syntax match typstMarkupRawInline
\ /`.\{-}`/
syntax region typstMarkupRawBlock
\ matchgroup=Macro start=/```\w*/
\ matchgroup=Macro end=/```/ keepend
syntax region typstCodeBlock
\ matchgroup=Macro start=/```typst/
\ matchgroup=Macro end=/```/ contains=@typstCode keepend
syntax include @C syntax/c.vim
syntax region typstMarkupCCodeBlock
\ matchgroup=Macro start=/```c\>/
\ matchgroup=Macro end=/```/ contains=@C keepend
syntax include @CPP syntax/cpp.vim
syntax region typstMarkupCPPCodeBlock
\ matchgroup=Macro start=/```cpp/
\ matchgroup=Macro end=/```/ contains=@CPP keepend
syntax include @Python syntax/python.vim
syntax region typstMarkupPythonCodeBlock
\ matchgroup=Macro start=/```python/
\ matchgroup=Macro end=/```/ contains=@Python keepend
syntax match typstMarkupLabel
\ /\v\<\K%(\k*-*)*\>/
syntax match typstMarkupReference
\ /\v\@\K%(\k*-*)*/
syntax match typstMarkupUrl
\ /http[s]\?:\/\/[[:alnum:]%\/_#.-]*/
syntax match typstMarkupHeading
\ /^\s*\zs=\{1,6}\s.*$/
\ contains=typstMarkupLabel,@Spell
syntax match typstMarkupBulletList
\ /\v^\s*-\s+/
syntax match typstMarkupEnumList
\ /\v^\s*(\+|\d+\.)\s+/
syntax match typstMarkupItalicError
\ /\v(\w|\\)@<!_\S@=.*/
syntax match typstMarkupItalic
\ /\v(\w|\\)@<!_\S@=.*(\n.+)*\S@<=\\@<!_/
\ contains=typstMarkupItalicRegion
syntax region typstMarkupItalicRegion
\ contained
\ matchgroup=typstMarkupItalicDelimiter start=/_/ skip=/\\\@<=_/ end=/_/
\ concealends contains=typstMarkupLabel,typstMarkupBold,@Spell
syntax region typstMarkupBold
\ matchgroup=typstMarkupBoldDelimiter start=/\*\S\@=/ skip=/\\\*/ end=/\S\@<=\*\|^$/
\ concealends contains=typstMarkupLabel,typstMarkupItalic,@Spell
syntax match typstMarkupLinebreak
\ /\\\\/
syntax match typstMarkupNonbreakingSpace
\ /\~/
syntax match typstMarkupShy
\ /-?/
syntax match typstMarkupDash
\ /-\{2,3}/
syntax match typstMarkupEllipsis
\ /\.\.\./
syntax match typstMarkupTermList
\ #\v^\s*\/\s+[^:]*:#
" Markup > Parens {{{2
syntax cluster typstMarkupParens
\ contains=typstMarkupDollar
syntax region typstMarkupDollar
\ matchgroup=Special start=/\$/ skip=/\\\$/ end=/\$/
\ contains=@typstMath
" Math {{{1
syntax cluster typstMath
\ contains=@typstCommon
\ ,@typstHashtag
\ ,typstMathFunction
\ ,typstMathNumber
\ ,typstMathSymbol
syntax match typstMathFunction
\ /\<\v\zs\a\w+\ze\(/
\ contained
syntax match typstMathNumber
\ /\<\d\+\>/
\ contained
" Math > Linked groups {{{2
highlight default link typstMathFunction Statement
highlight default link typstMathNumber Number
highlight default link typstMathSymbol Statement
" Highlighting {{{1
" Highlighting > Linked groups {{{2
highlight default link typstCommentBlock Comment
highlight default link typstCommentLine Comment
highlight default link typstCommentTodo Todo
highlight default link typstCodeConditional Conditional
highlight default link typstCodeRepeat Repeat
highlight default link typstCodeKeyword Keyword
highlight default link typstCodeConstant Constant
highlight default link typstCodeNumberInteger Number
highlight default link typstCodeNumberFloat Number
highlight default link typstCodeNumberLength Number
highlight default link typstCodeNumberAngle Number
highlight default link typstCodeNumberRatio Number
highlight default link typstCodeNumberFraction Number
highlight default link typstCodeString String
highlight default link typstCodeStatementWord Statement
highlight default link typstCodeIdentifier Identifier
highlight default link typstCodeFieldAccess Identifier
highlight default link typstCodeFunction Function
highlight default link typstCodeParen Noise
highlight default link typstCodeBrace Noise
highlight default link typstCodeBracket Noise
highlight default link typstCodeDollar Noise
highlight default link typstHashtagControlFlowError Error
highlight default link typstHashtagConditional Conditional
highlight default link typstHashtagRepeat Repeat
highlight default link typstHashtagKeyword Keyword
highlight default link typstHashtagConstant Constant
highlight default link typstHashtagStatementWord Statement
highlight default link typstHashtagIdentifier Identifier
highlight default link typstHashtagFieldAccess Identifier
highlight default link typstHashtagFunction Function
highlight default link typstHashtagParen Noise
highlight default link typstHashtagBrace Noise
highlight default link typstHashtagBracket Noise
highlight default link typstHashtagDollar Noise
highlight default link typstMarkupRawInline Macro
highlight default link typstMarkupRawBlock Macro
highlight default link typstMarkupLabel Structure
highlight default link typstMarkupReference Structure
highlight default link typstMarkupBulletList Structure
highlight default link typstMarkupItalicError Error
highlight default link typstMarkupEnumList Structure
highlight default link typstMarkupLinebreak Structure
highlight default link typstMarkupNonbreakingSpace Structure
highlight default link typstMarkupShy Structure
highlight default link typstMarkupDash Structure
highlight default link typstMarkupEllipsis Structure
highlight default link typstMarkupTermList Structure
highlight default link typstMarkupDollar Noise
" Highlighting > Custom Styling {{{2
highlight default typstMarkupHeading term=underline,bold cterm=underline,bold gui=underline,bold
highlight default typstMarkupUrl term=underline cterm=underline gui=underline
highlight default typstMarkupBold term=bold cterm=bold gui=bold
highlight default typstMarkupItalicRegion term=italic cterm=italic gui=italic
highlight default link typstMarkupBoldDelimiter typstMarkupBold
highlight default link typstMarkupItalicDelimiter typstMarkupItalic
" }}}1
let b:current_syntax = "typst"
" vim: foldlevel=0 tabstop=8 shiftwidth=4 softtabstop=4 expandtab

1
colors/nord.lua Normal file
View File

@ -0,0 +1 @@
require('user.util.color').load_theme('nord')

1
colors/onedark.lua Normal file
View File

@ -0,0 +1 @@
require('user.util.color').load_theme('onedark')

54
filetype.lua Normal file
View File

@ -0,0 +1,54 @@
vim.filetype.add {
filename = {
vifmrc = 'vim',
['.ansible-lint'] = 'yaml',
['.yamllint'] = 'yaml',
['ansible.cfg'] = 'ini',
['BUCK'] = 'bzl',
['flake.lock'] = 'json',
['go.mod'] = 'gomod',
['mopidy.conf'] = 'cfg',
['mpDris2.conf'] = 'cfg',
['mpd.conf'] = 'conf',
['terraform.tfstate'] = 'json',
},
extension = {
http = 'http',
hurl = 'hurl',
k = 'kcl',
mmd = 'mermaid',
ncl = 'nickel',
nft = 'nftables',
river = 'hcl',
templ = 'templ',
tmpl = 'gohtmltmpl',
typ = 'typst',
vifm = 'vim',
-- Jinja2
j2 = 'jinja',
jinja = 'jinja',
jinja2 = 'jinja',
-- Rescript
res = 'rescript',
resi = 'rescript',
},
pattern = {
['${HOME}/.kube/config'] = 'yaml',
-- Ansible
['.*/roles/.*/tasks/.*%.ya?ml'] = 'yaml.ansible',
['.*/roles/.*/handlers/.*%.ya?ml'] = 'yaml.ansible',
['.*/playbooks/.*%.ya?ml'] = 'yaml.ansible',
['playbook.ya?ml'] = 'yaml.ansible',
-- Waybar config
['${XDG_CONFIG_HOME}/waybar/config'] = 'jsonc',
-- Rofi style (not really CSS, but similar)
['${XDG_CONFIG_HOME}/rofi/.*%.rasi'] = 'css',
['${XDG_CONFIG_HOME}/rofi/.*%.rasinc'] = 'css',
['${XDG_CONFIG_HOME}/rofi/themes/.*%.rasi'] = 'css',
['${XDG_CONFIG_HOME}/rofi/themes/.*%.rasinc'] = 'css',
-- please.build
['%.?plzconfig'] = 'gitconfig',
['%.plzconfig_[%w_]+'] = 'gitconfig',
['%.plzconfig.[%w_%-]+'] = 'gitconfig',
},
}

25
go.mod Normal file
View File

@ -0,0 +1,25 @@
module nvim
go 1.20
require (
github.com/go-playground/validator/v10 v10.15.5
github.com/goccy/go-yaml v1.11.2
github.com/magefile/mage v1.15.0
github.com/sirupsen/logrus v1.9.3
)
require (
github.com/fatih/color v1.10.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)

54
go.sum Normal file
View File

@ -0,0 +1,54 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24=
github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ=
github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

35
init.lua Normal file
View File

@ -0,0 +1,35 @@
-- Configurations
require('user.config.options')
-- Load plugins with lazy.nvim
require('user.config.lazy')
-- Keymaps and Autocmds can wait
vim.api.nvim_create_autocmd('User', {
pattern = 'VeryLazy',
once = true,
callback = function()
require('user.config.autocmds')
require('user.config.keymap')
end,
group = vim.api.nvim_create_augroup('UserLazyConfig', { clear = true }),
})
-- Open nvim-tree on directory at start up
-- NOTE: the other autocmds are lazy-loaded, so this one can't be there
vim.api.nvim_create_autocmd('VimEnter', {
pattern = '*',
callback = function(args)
if vim.fn.isdirectory(args.file) == 1 then
-- create a new, empty buffer
vim.cmd.enew()
-- wipe the directory buffer
vim.cmd.bw(args.buf)
-- change to the directory
vim.cmd.cd(args.file)
-- open the tree (it will be autoloaded by lazy.nvim here)
require('nvim-tree.api').tree.open()
end
end,
group = vim.api.nvim_create_augroup('NvimTreeStartup', { clear = true }),
})

101
lazy-lock.json Normal file
View File

@ -0,0 +1,101 @@
{
"LuaSnip": { "branch": "master", "commit": "80a8528f084a97b624ae443a6f50ff8074ba486b" },
"SchemaStore.nvim": { "branch": "main", "commit": "976e7e3e9c400b99f1cb337b2ce804a9652571ec" },
"aerial.nvim": { "branch": "master", "commit": "3a3baf0930444c78d19964fdb401bd3a6a23270f" },
"alpha-nvim": { "branch": "main", "commit": "234822140b265ec4ba3203e3e0be0e0bb826dff5" },
"better-escape.nvim": { "branch": "master", "commit": "7031dc734add47bb71c010e0551829fa5799375f" },
"carbon-now.nvim": { "branch": "main", "commit": "3caa535a6216a8f3152708ae0fe6087b76e58639" },
"ccc.nvim": { "branch": "main", "commit": "cd2a10557b4a13e80929f59a7076ae792b2c60fa" },
"cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" },
"cmp-dap": { "branch": "master", "commit": "d16f14a210cd28988b97ca8339d504533b7e09a4" },
"cmp-fish": { "branch": "main", "commit": "8ae7bfb1b3251d433c4adf4e64396ef929fbd91f" },
"cmp-nvim-lsp": { "branch": "main", "commit": "44b16d11215dce86f253ce0c30949813c0a90765" },
"cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" },
"cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" },
"conform.nvim": { "branch": "master", "commit": "253878436e2b6d73dfd91ccf0ac12d04cc683d34" },
"dial.nvim": { "branch": "master", "commit": "019bbe9daea397c93a99adc747f8f071379fee5c" },
"diffview.nvim": { "branch": "main", "commit": "d38c1b5266850f77f75e006bcc26213684e1e141" },
"dressing.nvim": { "branch": "master", "commit": "1f2d1206a03bd3add8aedf6251e4534611de577f" },
"emmylua-nvim": { "branch": "master", "commit": "306432bb1179efc504ba3403a748c4967e9e8e0c" },
"flash.nvim": { "branch": "main", "commit": "48817af25f51c0590653bbc290866e4890fe1cbe" },
"friendly-snippets": { "branch": "main", "commit": "43727c2ff84240e55d4069ec3e6158d74cb534b6" },
"git-conflict.nvim": { "branch": "main", "commit": "896261933afe2fddf6fb043d9cd4d88301b151a9" },
"gitsigns.nvim": { "branch": "main", "commit": "af0f583cd35286dd6f0e3ed52622728703237e50" },
"headlines.nvim": { "branch": "master", "commit": "74a083a3c32a08be24f7dfcc6f448ecf47857f46" },
"heirline.nvim": { "branch": "master", "commit": "7f1e805dfc001d5dbb7d894105063f463f6c7dcc" },
"inc-rename.nvim": { "branch": "main", "commit": "ed0f6f2b917cac4eb3259f907da0a481b27a3b7e" },
"indent-blankline.nvim": { "branch": "master", "commit": "64fdadb3ada61c4297452f7662789b01ee82ffcb" },
"iswap.nvim": { "branch": "master", "commit": "e05889db694524f68eb69567a70a98470994b890" },
"lazy.nvim": { "branch": "main", "commit": "16603c6917435d8446f7357cb61095138a417085" },
"lsp_lines.nvim": { "branch": "main", "commit": "9e3f99fbbd28aaec80dc0158c43be8cca8dd5017" },
"markdown-preview.nvim": { "branch": "master", "commit": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee" },
"mini.ai": { "branch": "main", "commit": "fc9ce93eb8d58ce1a39101928fb5ea8f8b97844c" },
"mini.align": { "branch": "main", "commit": "e3a0c114d3fea0479f8e8ee3e273c7ca4ba6ea8d" },
"mini.animate": { "branch": "main", "commit": "6e6f2ee99fec91985d3817bfc74fbb4a0aff1c44" },
"mini.bufremove": { "branch": "main", "commit": "f53c7f27e36009fe61563c11cde154b94a0e5b94" },
"mini.comment": { "branch": "main", "commit": "e4320af992cd053a7da2f33d9f63a86c2ab6ce59" },
"mini.move": { "branch": "main", "commit": "b3bca8e493f8d1da343ff1be06c21a47e2fde1c0" },
"mini.pairs": { "branch": "main", "commit": "6f6bd7ed5757b40bc29c73dac0d743e4e6978124" },
"mini.surround": { "branch": "main", "commit": "862cfaef72d789d320625ec34e2488a5cc8fd423" },
"neoconf.nvim": { "branch": "main", "commit": "00dcf2b81c45de1768b4171faa16729f0888cfb8" },
"neogen": { "branch": "main", "commit": "70127baaff25611deaf1a29d801fc054ad9d2dc1" },
"neogit": { "branch": "master", "commit": "05899be06d611c485cfb6e17ef6e3b695de67b62" },
"neotest": { "branch": "master", "commit": "901891484db3d46ce43d56871273dc7d40621356" },
"neotest-go": { "branch": "main", "commit": "1a15e1136db43775214a3e7a598f8930c29c94b7" },
"neotest-jest": { "branch": "main", "commit": "65ab61c77aa1c245f16982ffe1a4d31589e18023" },
"neotest-python": { "branch": "master", "commit": "81d2265efac717bb567bc15cc652ae10801286b3" },
"neotest-vitest": { "branch": "main", "commit": "41bf2f6b743f2ac5c5e9bd0949cee77ca7f2372c" },
"neotest-zig": { "branch": "main", "commit": "f546293bdb85ae1ff872d617a54eefa65479fd8f" },
"noice.nvim": { "branch": "main", "commit": "92433164e2f7118d4122c7674c3834d9511722ba" },
"nui.nvim": { "branch": "main", "commit": "c0c8e347ceac53030f5c1ece1c5a5b6a17a25b32" },
"nvim-cmp": { "branch": "main", "commit": "51260c02a8ffded8e16162dcf41a23ec90cfba62" },
"nvim-cokeline": { "branch": "main", "commit": "2e71292a37535fdbcf0f9500aeb141021d90af8b" },
"nvim-coverage": { "branch": "main", "commit": "13e357d4a2a230070c64ede61252225f0b7d3b5e" },
"nvim-dap": { "branch": "master", "commit": "79dbc70eb79271ad801e4ff293887cde324c28d0" },
"nvim-dap-ui": { "branch": "master", "commit": "34160a7ce6072ef332f350ae1d4a6a501daf0159" },
"nvim-dap-virtual-text": { "branch": "master", "commit": "57f1dbd0458dd84a286b27768c142e1567f3ce3b" },
"nvim-lint": { "branch": "master", "commit": "962a76877a4479a535b935bd7ef35ad41ba308b2" },
"nvim-lspconfig": { "branch": "master", "commit": "cb49a4cd622d7ed775c31561bb8aa6a50712d6b9" },
"nvim-navic": { "branch": "master", "commit": "0ffa7ffe6588f3417e680439872f5049e38a24db" },
"nvim-notify": { "branch": "master", "commit": "e4a2022f4fec2d5ebc79afa612f96d8b11c627b3" },
"nvim-scrollbar": { "branch": "main", "commit": "35f99d559041c7c0eff3a41f9093581ceea534e8" },
"nvim-spectre": { "branch": "master", "commit": "696cff781a4a7ecc91549736835e2acbd00fe859" },
"nvim-tree.lua": { "branch": "master", "commit": "78a9ca5ed6557f29cd0ce203df44213e54bfabb9" },
"nvim-treesitter": { "branch": "master", "commit": "bf0a96568a54618138ac42c84758945cdafef86b" },
"nvim-treesitter-context": { "branch": "master", "commit": "2806d83e3965017382ce08792ee527e708fa1bd4" },
"nvim-treesitter-textobjects": { "branch": "master", "commit": "e69a504baf2951d52e1f1fbb05145d43f236cbf1" },
"nvim-ts-autotag": { "branch": "main", "commit": "6be1192965df35f94b8ea6d323354f7dc7a557e4" },
"nvim-ts-context-commentstring": { "branch": "main", "commit": "92e688f013c69f90c9bbd596019ec10235bc51de" },
"nvim-web-devicons": { "branch": "master", "commit": "5de460ca7595806044eced31e3c36c159a493857" },
"orgmode": { "branch": "master", "commit": "a6fc6b224188c519fa4e9c0beddd5f3b22575d6e" },
"overseer.nvim": { "branch": "master", "commit": "95bd2d45af543238e25919ad2d9793a8cf61ac38" },
"pantran.nvim": { "branch": "main", "commit": "461799624948bfb66f73b20b6fffa7e4c8ca6d08" },
"parinfer-rust": { "branch": "master", "commit": "0e4d52e712641ad351a1bfe6cee3d34d63ed087b" },
"persistence.nvim": { "branch": "main", "commit": "ad538bfd5336f1335cdb6fd4e0b0eebfa6e12f32" },
"plenary.nvim": { "branch": "master", "commit": "50012918b2fc8357b87cff2a7f7f0446e47da174" },
"project.nvim": { "branch": "main", "commit": "8c6bad7d22eef1b71144b401c9f74ed01526a4fb" },
"rainbow-delimiters.nvim": { "branch": "master", "commit": "9fda1322e704acfbb5a9691e2c4303368d591367" },
"rest.nvim": { "branch": "main", "commit": "b8d6c0a8762fd374e0204768a94241135ca3e311" },
"scope.nvim": { "branch": "main", "commit": "01ce40fe7434fba9a122c01b4734479b3860609a" },
"sniprun": { "branch": "master", "commit": "0ad935699a5e24ca3a0aa621c7425ac7029775b3" },
"ssr.nvim": { "branch": "main", "commit": "bb323ba621ac647b4ac5638b47666e3ef3c279e1" },
"stickybuf.nvim": { "branch": "master", "commit": "f3398f8639e903991acdf66e2d63de7a78fe708e" },
"telescope-file-browser.nvim": { "branch": "master", "commit": "6e51d0cd6447cf2525412220ff0a2885eef9039c" },
"telescope-fzf-native.nvim": { "branch": "main", "commit": "6c921ca12321edaa773e324ef64ea301a1d0da62" },
"telescope-symbols.nvim": { "branch": "master", "commit": "f2060117d965df4a626f068a4ebbd8ee051aa076" },
"telescope-tabs": { "branch": "master", "commit": "a38c8fee471257a0ff233e065c4a0d123f8e67b0" },
"telescope.nvim": { "branch": "master", "commit": "4522d7e3ea75ffddabdc39957168a8a7060b5df0" },
"todo-comments.nvim": { "branch": "main", "commit": "4a6737a8d70fe1ac55c64dfa47fcb189ca431872" },
"toggleterm.nvim": { "branch": "main", "commit": "c80844fd52ba76f48fabf83e2b9f9b93273f418d" },
"treesj": { "branch": "main", "commit": "070e6761d0b11a55446d988a69908f7a0928dbab" },
"trouble.nvim": { "branch": "main", "commit": "f1168feada93c0154ede4d1fe9183bf69bac54ea" },
"twilight.nvim": { "branch": "main", "commit": "8b7b50c0cb2dc781b2f4262a5ddd57571556d1e4" },
"undotree": { "branch": "master", "commit": "3ff3aa02fd3a18d7fc5be9ed3166d36c545707fe" },
"venn.nvim": { "branch": "main", "commit": "c114563960b8fb1197695d42798d1f3e7190b798" },
"vim-log-highlighting": { "branch": "master", "commit": "1037e26f3120e6a6a2c0c33b14a84336dee2a78f" },
"vim-matchup": { "branch": "master", "commit": "6dbe108230c7dbbf00555b7d4d9f6a891837ef07" },
"vim-repeat": { "branch": "master", "commit": "24afe922e6a05891756ecf331f39a1f6743d3d5a" },
"vim-startuptime": { "branch": "master", "commit": "454b3de856b7bd298700de33d79774ca9b9e3875" },
"which-key.nvim": { "branch": "main", "commit": "4433e5ec9a507e5097571ed55c02ea9658fb268a" },
"zen-mode.nvim": { "branch": "main", "commit": "50e2e2a36cc97847d9ab3b1a3555ba2ef6839b50" }
}

View File

@ -0,0 +1,118 @@
local group = vim.api.nvim_create_augroup('UserAutoCmds', { clear = true })
local function close_with_q(buf)
vim.bo[buf].buflisted = false
vim.keymap.set('n', 'q', '<cmd>close<CR>', { buffer = buf, silent = true })
end
-- Close some filetypes with <q> and auto delete buffer for them
vim.api.nvim_create_autocmd('FileType', {
pattern = {
'qf',
'help',
'man',
'query',
'notify',
'spectre_panel',
'neotest-output',
'neotest-output-panel',
'neotest-summary',
'startuptime',
'PlenaryTestPopup',
},
callback = function(args)
close_with_q(args.buf)
end,
group = group,
})
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'checkhealth', 'log' },
callback = function(args)
-- Only do this to Neovim related log files
if vim.api.nvim_buf_get_option(args.buf, 'filetype') == 'log'
and vim.fn.expand('%:p:h') ~= vim.fn.stdpath('log')
then
return
end
vim.bo[args.buf].bufhidden = 'delete'
close_with_q(args.buf)
end,
group = group,
})
vim.api.nvim_create_autocmd('FileType', {
pattern = { 'gitcommit', 'gitrebase' },
callback = function(args)
vim.bo[args.buf].bufhidden = 'wipe'
vim.opt_local.colorcolumn = { 80 }
end,
group = group,
})
-- Show cursor line only in active window
vim.api.nvim_create_autocmd('WinEnter', {
callback = function()
local ok, cl = pcall(vim.api.nvim_win_get_var, 0, 'cursorline')
if ok and cl then
vim.wo.cursorline = true
vim.api.nvim_win_del_var(0, 'cursorline')
end
end,
group = group,
})
vim.api.nvim_create_autocmd('WinLeave', {
callback = function()
local cl = vim.wo.cursorline
if cl then
vim.api.nvim_win_set_var(0, 'cursorline', cl)
vim.wo.cursorline = false
end
end,
group = group,
})
-- No undo history for temporary files
vim.api.nvim_create_autocmd('BufWritePre', {
pattern = { '/tmp/*', 'COMMIT_EDITMSG', 'MERGE_MSG', '*.tmp', '*.bak' },
callback = function()
vim.opt_local.undofile = false
end,
group = group,
})
-- Equalize window sizes when resizing the terminal
vim.api.nvim_create_autocmd('VimResized', {
pattern = '*',
command = 'tabdo wincmd =',
group = group,
})
-- Force writing shada file on leaving
vim.api.nvim_create_autocmd('VimLeave', {
pattern = '*',
command = 'if has("nvim") | wshada! | else | wviminfo! | endif',
group = group,
})
-- Check if we need to reload the file when it changed
vim.api.nvim_create_autocmd({ 'FocusGained', 'TermClose', 'TermLeave' }, {
pattern = '*',
command = 'checktime',
group = group,
})
-- Highlight region on yank
vim.api.nvim_create_autocmd('TextYankPost', {
pattern = '*',
callback = function()
vim.highlight.on_yank { higroup = 'IncSearch', timeout = 300 }
end,
group = group,
})
-- Wrap in Telescope's preview buffer
vim.api.nvim_create_autocmd('User', {
pattern = 'TelescopePreviewerLoaded',
callback = function()
vim.opt_local.wrap = true
end,
group = group,
})

View File

@ -0,0 +1,88 @@
local util = require('user.util.misc')
local map = vim.keymap.set
-- better up/down
map({ 'n', 'x' }, 'j', 'v:count == 0 ? "gj" : "j"', { expr = true, silent = true })
map({ 'n', 'x' }, 'k', 'v:count == 0 ? "gk" : "k"', { expr = true, silent = true })
-- better indenting
map('v', '<', '<gv')
map('v', '>', '>gv')
-- remove trailing whitespaces
map('n', '<localleader>w', '<cmd>%s/\\s\\+$//e<CR>', { desc = 'Remove whitespaces' })
-- Resize window using <ctrl> + arrow keys
map('n', '<C-Up>', '<cmd>resize +2<CR>', { desc = 'Increase window height' })
map('n', '<C-Down>', '<cmd>resize -2<CR>', { desc = 'Decrease window height' })
map('n', '<C-Left>', '<cmd>vertical resize -2<CR>', { desc = 'Decrease window width' })
map('n', '<C-Right>', '<cmd>vertical resize +2<CR>', { desc = 'Increase window width' })
-- H, L instead of 0, $
-- map({ 'n', 'x', 'o' }, 'H', '0')
-- map({ 'n', 'x', 'o' }, 'L', '$')
-- Clear search with <Esc>
map({ 'i', 'n' }, '<Esc>', '<cmd>noh<CR><Esc>', { desc = 'Escape and clear hlsearch' })
-- More intuitive n/N direction
-- https://github.com/mhinz/vim-galore#saner-behavior-of-n-and-n
map('n', 'n', '"Nn"[v:searchforward]', { expr = true, desc = 'Next search result' })
map('x', 'n', '"Nn"[v:searchforward]', { expr = true, desc = 'Next search result' })
map('o', 'n', '"Nn"[v:searchforward]', { expr = true, desc = 'Next search result' })
map('n', 'N', '"nN"[v:searchforward]', { expr = true, desc = 'Prev search result' })
map('x', 'N', '"nN"[v:searchforward]', { expr = true, desc = 'Prev search result' })
map('o', 'N', '"nN"[v:searchforward]', { expr = true, desc = 'Prev search result' })
-- switching between buffers
if not util.has('nvim-cokeline') then
map('n', ']b', '<cmd>bnext<CR>', { desc = 'Next buffer' })
map('n', '[b', '<cmd>bprevious<CR>', { desc = 'Previous buffer' })
end
-- move between quickfix items
if not util.has('trouble.nvim') then
map('n', '[q', vim.cmd.cprev, { desc = 'Previous quickfix' })
map('n', ']q', vim.cmd.cnext, { desc = 'Next quickfix' })
end
-- toggle LSP settings
map('n', '<leader>ud', require('user.plugins.lsp.lspconfig.diagnostic').toggle, { desc = 'Toggle diagnostics' })
map('n', '<leader>uv', require('user.plugins.lsp.lspconfig.diagnostic').toggle_virtual_lines, { desc = 'Toggle virtual lines diagnostics' })
map('n', '<leader>uf', require('user.plugins.lsp.lspconfig.format').toggle, { desc = 'Toggle format on save' })
if vim.lsp.inlay_hint then
map('n', '<leader>uy', function() vim.lsp.inlay_hint(0, nil) end, { desc = 'Toggle inlay hints' })
end
-- toggle editor settings
map('n', '<leader>ur', function() util.toggle('relativenumber', true) end, { desc = 'Toggle relativenumber' })
map('n', '<leader>ue', function() util.toggle('conceallevel', false, { 0, vim.go.conceallevel > 0 and vim.go.conceallevel or 3 }) end, { desc = 'Toggle conceallevel' })
map('n', '<leader>us', function() util.toggle('expandtab') end, { desc = 'Toggle tab/space indent' })
-- exit
map('n', '<leader>qw', '<C-w>c', { desc = 'Delete window' })
map('n', '<leader>qq', '<cmd>qa<CR>', { desc = 'Quit all' })
-- get highlight groups under cursor
map('n', '<leader>up', vim.show_pos, { desc = 'Inspect pos' })
map('n', '<leader>ut', vim.treesitter.inspect_tree, { desc = 'Inspect treesitter' })
-- escape in terminal mode
map('t', '<Esc><Esc>', '<C-\\><C-n>', { desc = 'Enter Normal mode' })
-- easier window split
map('n', '<leader>-', '<C-w>s', { desc = 'Split window below' })
map('n', '<leader>|', '<C-w>v', { desc = 'Split window right' })
-- tabs
map('n', '<leader><Tab>l', '<cmd>tablast<CR>', { desc = 'Last tab' })
map('n', '<leader><Tab>f', '<cmd>tabfirst<CR>', { desc = 'First tab' })
map('n', '<leader><Tab><Tab>', '<cmd>tabnew<CR>', { desc = 'New tab' })
map('n', '<leader><Tab>]', '<cmd>tabnext<CR>', { desc = 'Next tab' })
map('n', '<leader><Tab>d', '<cmd>tabclose<CR>', { desc = 'Close tab' })
map('n', '<leader><Tab>[', '<cmd>tabprevious<CR>', { desc = 'Previous tab' })
map('n', '<leader><Tab>n', '<cmd>+tabmove<CR>', { desc = 'Move tab next' })
map('n', '<leader><Tab>p', '<cmd>-tabmove<CR>', { desc = 'Move tab previous' })
-- open Lazy UI
map('n', '<leader><Space>', '<cmd>Lazy<CR>', { desc = 'Lazy' })

59
lua/user/config/lazy.lua Normal file
View File

@ -0,0 +1,59 @@
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
vim.fn.system {
'git',
'clone',
'--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
lazypath,
}
-- Use specific commit of lazy.nvim if defined
local f = io.open(vim.fn.stdpath('config') .. '/lazy-lock.json', 'r')
if f then
local lock = vim.json.decode(f:read('*a'))
vim.fn.system { 'git', '-C', lazypath, 'checkout', lock['lazy.nvim'].commit }
end
end
vim.opt.rtp:prepend(lazypath)
local opts = {
install = { colorscheme = { 'nord', 'onedark', 'habamax' } },
defaults = { lazy = true },
ui = {
wrap = false,
size = { width = 0.9, height = 0.85 },
border = require('user.config.vars').border,
},
checker = { enabled = false, notify = false },
change_detection = { enabled = true, notify = false },
performance = {
cache = { enabled = true },
reset_packpath = true,
rtp = {
reset = true,
disabled_plugins = {
'gzip',
'matchit',
'matchparen',
'netrw',
'netrwFilHandlers',
'netrwPlugin',
'netrwSettings',
'netrw_gitignore',
'rplugin',
'spellfile',
'sqlcomplete',
'syntaxcomplete',
'tar',
'tarPlugin',
'tohtml',
'tutor',
'zip',
'zipPlugin',
},
},
},
}
require('lazy').setup('user.plugins', opts)

178
lua/user/config/options.lua Normal file
View File

@ -0,0 +1,178 @@
local global_vars = {
-- Leader keys
mapleader = ' ',
maplocalleader = '\\',
-- TeX flavor
tex_flavor = 'latex',
}
local vim_options = {
-- General settings
termguicolors = true,
background = 'dark',
mouse = 'nv',
errorbells = false,
visualbell = false,
confirm = true,
fileformats = 'unix',
magic = true,
virtualedit = 'block',
encoding = 'utf-8',
fileencoding = 'utf-8',
clipboard = { 'unnamed', 'unnamedplus' },
wildignorecase = true,
wildignore = {
'.DS_Store',
'.git',
'.hg',
'.svn',
'*.pyc',
'*.o',
'*.obj',
'*.out',
'*.ico',
'*.jar',
'*.jpg',
'*.jpeg',
'*.png',
'*.gif',
'*.avi',
'*.wav',
'*.zip',
'**/tmp/**',
'**/node_modules/**',
'**/bazel-out/**',
'**/bazel-bin/**',
'**/bazel-testlogs/**',
'**/plz-out/**',
'**/.plz-cache/**',
'**/.plz-http-cache/**',
},
showmode = false,
sessionoptions = { 'buffers', 'curdir', 'tabpages', 'winsize' },
jumpoptions = 'stack',
formatoptions = '1jcroqlnt',
wrap = false,
sidescrolloff = 4,
scrolloff = 4,
whichwrap = {
['<'] = true,
['>'] = true,
['['] = true,
[']'] = true,
['~'] = true,
},
splitkeep = 'screen',
-- colorcolumn = { 120 },
-- cursorcolumn = true,
cursorline = true,
cursorlineopt = { 'number' },
backspace = { 'indent', 'eol', 'start' },
showcmd = false,
cmdheight = 0,
showtabline = 2,
laststatus = 3,
synmaxcol = 2500,
grepformat = '%f:%l:%c:%m',
grepprg = 'rg --hidden --vimgrep --smart-case --',
diffopt = { 'filler', 'iwhite', 'internal', 'algorithm:patience' },
-- CVE-2019-12735 (it is patched, but just to be cautious)
-- I don't use modeline personally anyway
modeline = false,
modelines = 0,
-- Spell checking, dictionary
-- spell = true,
-- spellfile = vim.fn.stdpath('config') .. '/spell/en.utf-8.add',
-- dictionary = { '/usr/share/dict/american-english' },
-- Transparency
pumblend = 0,
winblend = 0,
-- Conceal
conceallevel = 2,
concealcursor = 'nc',
foldenable = false,
foldlevelstart = 99,
-- Case insensitive
ignorecase = true,
smartcase = true,
infercase = true,
-- Update time
timeoutlen = 500,
ttimeoutlen = 25,
updatetime = 150,
redrawtime = 1500,
-- No swapfile
backup = false,
writebackup = false,
swapfile = false,
-- Completion menu
wildmode = 'longest:full,full',
complete = { '.', 'w', 'b', 'k' },
completeopt = { 'menu', 'menuone', 'noselect' },
pumheight = 16,
helpheight = 12,
previewheight = 12,
-- Window rules
splitbelow = true,
splitright = true,
switchbuf = 'useopen',
winwidth = 30,
winminwidth = 10,
equalalways = false,
-- Left column
signcolumn = 'auto:6',
number = true,
relativenumber = true,
-- numberwidth = 6,
-- 4 spaces = 1 tab
tabstop = 4,
-- softtabstop = -1, -- use the value of 'shiftwidth'
shiftwidth = 0, -- use the value of 'tabstop'
expandtab = true,
smartindent = true,
shiftround = true,
-- Trailings, line break
list = true,
listchars = {
tab = '»·',
nbsp = '+',
trail = '·',
extends = '',
precedes = '',
},
showbreak = '',
-- linebreak = true,
-- breakat = [[\ \ ;:,!?]],
breakindent = true,
-- breakindentopt = { shift = 4, min = 20 },
-- Undo file path
undofile = true,
undolevels = 10000,
}
-- Load global variables
for k, v in pairs(global_vars) do
vim.g[k] = v
end
-- Load editor options
for k, v in pairs(vim_options) do
vim.opt[k] = v
end
-- Special treats
vim.opt.shortmess:append { W = true, I = true, c = true, C = true }

87
lua/user/config/vars.lua Normal file
View File

@ -0,0 +1,87 @@
local M = {}
M.border = 'rounded'
M.rg_args = { '--hidden', '--color=never', '--no-heading', '--with-filename', '--line-number', '--column' }
-- Log level used for nvim-notify and LSP log
M.loglevel = vim.log.levels.INFO
-- Some default LSP options (can be toggled)
M.lsp_format_on_save = false
M.lsp_virtual_lines = true
M.lsp_inlay_hints = true
M.lsp_document_highlight = true
-- Only 'bottom_pane', 'horizontal' or 'cursor' right now
M.telescope_layout = 'horizontal'
-- 'tabby' or 'cokeline'
M.tabline_provider = 'cokeline'
-- Where to install tree-sitter parsers (will be added to rtp)
M.ts_parsers_path = vim.fn.stdpath('data') .. '/parsers'
M.icons = {
notify = { -- also used for diagnostic signs
error = '',
hint = '',
info = '',
warn = '',
debug = '',
trace = '',
},
git = {
added = '',
modified = '',
removed = '',
},
dap = {
Stopped = { '', 'DiagnosticWarn', 'Visual' },
Breakpoint = '',
BreakpointCondition = { '', 'DiagnosticHint' },
BreakpointRejected = { '', 'DiagnosticError' },
LogPoint = '',
},
kind = {
-- aerial.nvim, nvim-navic
File = { icon = '', hl = '@text.uri' },
Module = { icon = '', hl = '@namespace' },
Namespace = { icon = '', hl = '@namespace' },
Package = { icon = '', hl = '@namespace' },
Class = { icon = '', hl = '@storageclass' },
Method = { icon = '', hl = '@method' },
Property = { icon = '', hl = '@property' },
Field = { icon = '', hl = '@field' },
Constructor = { icon = '󰒓', hl = '@constructor' },
Enum = { icon = '', hl = '@lsp.type.enum' },
Interface = { icon = '', hl = '@lsp.type.interface' },
Function = { icon = '󰡱', hl = '@function' },
Variable = { icon = '', hl = '@variable' },
Constant = { icon = '', hl = '@constant' },
String = { icon = '', hl = '@string' },
Number = { icon = '', hl = '@number' },
Boolean = { icon = '', hl = '@boolean' },
Array = { icon = '', hl = '@constant' },
Object = { icon = '', hl = '@type' },
Key = { icon = '󰌋', hl = '@type' },
Null = { icon = '󰟢', hl = '@none' },
EnumMember = { icon = '', hl = '@constant' },
Struct = { icon = '', hl = '@lsp.type.struct' },
Event = { icon = '', hl = '@type' },
Operator = { icon = '', hl = '@operator' },
TypeParameter = { icon = '', hl = '@parameter' },
-- Additional ones for nvim-cmp.
-- No need to specify the highlights here.
Text = { icon = '' },
Unit = { icon = '' },
Value = { icon = '' },
Keyword = { icon = '' },
Snippet = { icon = '' },
Color = { icon = '' },
Reference = { icon = '' },
Folder = { icon = '' },
},
}
return M

View File

@ -0,0 +1,139 @@
local cmp, luasnip = require('cmp'), require('luasnip')
local vars = require('user.config.vars')
local sources_config = {
buffer = { item_menu = 'BUF', option = { keyword_length = 2 } },
dap = { item_menu = 'DAP' },
fish = { item_menu = 'FISH' },
luasnip = { item_menu = 'SNIP' },
nvim_lsp = { item_menu = 'LSP' },
orgmode = { item_menu = 'ORG' },
path = { item_menu = 'PATH' },
}
local sources = vim.deepcopy(sources_config)
for source, _ in pairs(sources_config) do
sources[source].name = source
sources[source].item_menu = nil
end
local has_words_before = function()
local line, col = unpack(vim.api.nvim_win_get_cursor(0))
return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match('%s') == nil
end
local cmpkind_icons = {}
for kind, spec in pairs(vars.icons.kind) do
cmpkind_icons[kind] = spec.icon
end
cmp.setup {
view = { entries = { name = 'custom', selection_order = 'near_cursor' } },
window = {
documentation = {
border = vars.border,
winhighlight = 'NormalFloat:NormalFloat,FloatBorder:FloatBorder',
},
completion = {
scrollbar = true,
border = vars.border,
winhighlight = 'NormalFloat:NormalFloat,FloatBorder:FloatBorder',
completeopt = 'menu,menuone,noinsert',
keyword_pattern = [[\%(-\?\d\+\%(\.\d\+\)\?\|\h\w*\%(-\w*\)*\)]],
keyword_length = 1,
},
},
formatting = {
fields = { 'kind', 'abbr', 'menu' },
format = function(entry, vim_item)
vim_item.menu = sources_config[entry.source.name].item_menu
if vim.tbl_contains({ 'path' }, entry.source.name) then
local icon, hl_group = require('nvim-web-devicons').get_icon(entry:get_completion_item().label)
if icon then
vim_item.kind = icon
vim_item.kind_hl_group = hl_group
return vim_item
end
end
vim_item.kind = cmpkind_icons[vim_item.kind] .. ' '
return vim_item
end,
},
mapping = {
['<CR>'] = cmp.mapping.confirm {
behavior = cmp.ConfirmBehavior.Replace,
select = true,
},
['<C-Space>'] = cmp.mapping.complete(),
['<C-p>'] = cmp.mapping.select_prev_item { behavior = cmp.SelectBehavior.Select },
['<C-n>'] = cmp.mapping.select_next_item { behavior = cmp.SelectBehavior.Select },
['<C-b>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-c>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.close()
else
fallback()
end
end),
-- Change choice nodes for luasnip
['<C-s>'] = cmp.mapping(function(fallback)
if luasnip.choice_active() then
luasnip.change_choice(1)
else
fallback()
end
end, { 'i', 's' }),
-- supertab-like mapping
['<Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item { behavior = cmp.SelectBehavior.Insert }
elseif luasnip.expand_or_jumpable() then
luasnip.expand_or_jump()
elseif has_words_before() then
cmp.complete()
else
fallback()
end
end, { 'i', 's' }),
['<S-Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item { behavior = cmp.SelectBehavior.Insert }
elseif luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { 'i', 's' }),
},
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
sources = cmp.config.sources {
sources.nvim_lsp,
sources.buffer,
sources.luasnip,
sources.path,
},
}
-- Filetype-based completion sources
cmp.setup.filetype({ 'dap-repl', 'dapui_watches', 'dapui_hover' }, {
sources = { sources.dap, sources.buffer },
})
cmp.setup.filetype('fish', {
sources = { sources.fish, sources.buffer, sources.path },
})
cmp.setup.filetype('org', {
sources = cmp.config.sources {
sources.orgmode,
sources.nvim_lsp,
sources.luasnip,
sources.buffer,
sources.path,
},
})

View File

@ -0,0 +1,55 @@
return {
{ 'mtoohey31/cmp-fish', ft = 'fish' },
{ 'rcarriga/cmp-dap', ft = { 'dap-repl', 'dapui_watches', 'dapui_hover' } },
{
'hrsh7th/nvim-cmp',
event = 'InsertEnter',
dependencies = {
'hrsh7th/cmp-buffer',
'hrsh7th/cmp-path',
'hrsh7th/cmp-nvim-lsp',
'saadparwaiz1/cmp_luasnip',
{
'L3MON4D3/LuaSnip',
dependencies = 'rafamadriz/friendly-snippets',
config = function()
require('user.plugins.completion.luasnip')
end,
},
},
config = function()
require('user.plugins.completion.cmp')
end,
},
{
'ii14/emmylua-nvim',
-- we only care about the EmmyLua files (loaded by lua-language-server)
init = function()
require('lazy.core.loader').disable_rtp_plugin('emmylua-nvim')
end,
},
{
'TabbyML/tabby',
event = 'InsertEnter',
cmd = 'Tabby',
enabled = vim.loop.os_uname().sysname == 'Darwin', -- I don't use NVIDIA, so only use this plugin on M1/M2 machines
init = function()
local config = {
tabby_server_url = 'http://127.0.0.1:10069',
tabby_enable = false,
tabby_suggestion_delay = vim.opt.updatetime:get(),
tabby_accept_binding = "<C-]>",
tabby_dismiss_binding = "<A-]>",
}
for k, v in pairs(config) do
vim.g[k] = v
end
end,
config = function(plugin)
require('lazy.core.loader').disable_rtp_plugin('tabby')
vim.opt.rtp:append(plugin.dir .. "/clients/vim")
end,
},
}

View File

@ -0,0 +1,17 @@
local types = require('luasnip.util.types')
require('luasnip').config.set_config {
updateevents = 'InsertLeave',
history = true,
ext_opts = {
[types.choiceNode] = {
active = { virt_text = { { '', 'LuasnipChoiceNodeActive' } } },
},
[types.insertNode] = {
active = { virt_text = { { '', 'LuasnipInsertNodeActive' } } },
},
},
}
-- Loading snippets from 'friendly-snippets'
require('luasnip.loaders.from_vscode').lazy_load()

View File

@ -0,0 +1,41 @@
local styles = {
single = {
topleft = '',
topright = '',
top = '',
left = '',
right = '',
botleft = '',
botright = '',
bot = '',
},
rounded = {
topleft = '',
topright = '',
top = '',
left = '',
right = '',
botleft = '',
botright = '',
bot = '',
},
double = {
topleft = '',
topright = '',
top = '',
left = '',
right = '',
botleft = '',
botright = '',
bot = '',
},
}
return {
summary = {
min_coverage = 75.0,
width_percentage = 0.8,
borders = styles[require('user.config.vars').border],
window = { winblend = 0 },
},
}

View File

@ -0,0 +1,46 @@
local dap = require('dap')
local debugpy_path = vim.fn.stdpath('data') .. '/dap/debugpy'
dap.adapters.python = function(callback, config)
if config.request == 'attach' then
local port = (config.connect or config).port
local host = (config.connect or config).host or '127.0.0.1'
callback {
type = 'server',
port = assert(port, '`connect.port` is required for a python `attach` configuration'),
host = host,
options = { source_filetype = 'python' },
}
return
end
callback {
type = 'executable',
command = debugpy_path .. '/bin/python',
args = { '-m', 'debugpy.adapter' },
options = { source_filetype = 'python' },
}
end
dap.configurations.python = {
{
name = 'Launch file',
type = 'python',
request = 'launch',
program = '${file}',
pythonPath = function()
local cwd, venv, conda = vim.fn.getcwd(), vim.env.VIRTUAL_ENV, vim.env.CONDA_PREFIX
if venv and vim.fn.executable(venv .. '/bin/python') == 1 then
return venv .. '/bin/python'
elseif conda and vim.fn.executable(conda .. '/bin/python') == 1 then
return conda .. '/bin/python'
elseif vim.fn.executable(cwd .. '/venv/bin/python') then
return cwd .. '/venv/bin/python'
elseif vim.fn.executable(cwd .. '/.venv/bin/python') then
return cwd .. '/.venv/bin/python'
else
return '/usr/bin/python'
end
end,
},
}

View File

@ -0,0 +1,152 @@
local dap = require('dap')
local lazy_util = require('lazy.core.util')
-- Default port to attach to an existing Delve instance
local delve_port = 38697
local get_arguments = function()
local co = coroutine.running()
local args = {}
if co then
return coroutine.create(function()
vim.ui.input({ prompt = 'Args: ' }, function(input)
args = vim.split(input or '', ' ')
end)
coroutine.resume(co, args)
end)
end
vim.ui.input({ prompt = 'Args: ' }, function(input)
args = vim.split(input or '', ' ')
end)
return args
end
local get_connection = function()
local co = coroutine.running()
local response = {}
if co then
return coroutine.create(function()
vim.ui.input({ prompt = 'Connection: ' }, function(input)
response = vim.split(input or ('127.0.0.1:' .. delve_port), ':')
end)
coroutine.resume(co, { host = response[1], port = response[2] or delve_port })
end)
end
vim.ui.input({ prompt = 'Connection: ' }, function(input)
response = vim.split(input or ('127.0.0.1:' .. delve_port), ':')
end)
return { host = response[1], port = response[2] or delve_port }
end
-- https://github.com/ray-x/go.nvim/blob/master/lua/go/dap.lua
dap.adapters.go = function(callback, config)
local host = (config.connect or config).host or '127.0.0.1'
if config.request == 'attach' and config.mode == 'remote' then
callback {
type = 'server',
host = host,
port = (config.connect or config).port or delve_port,
}
return
end
-- Randomize a random port number to launch Delve with
math.randomseed(os.time())
local port = (config.connect or config).port or (38000 + math.random(1, 1000))
local stdout = vim.loop.new_pipe(false)
local stderr = vim.loop.new_pipe(false)
local handle, pid_or_err
local function on_read(err, chunk)
assert(not err, err)
if not chunk or chunk == '' then return end
if chunk:find("couldn't start") then
vim.schedule(function()
lazy_util.error(chunk, { title = '[go] DAP Error' })
end)
end
vim.schedule(function()
require('dap.repl').append(chunk)
end)
end
handle, pid_or_err = vim.loop.spawn('dlv', {
stdio = { nil, stdout, stderr },
args = { 'dap', '--listen', string.format('%s:%s', host, port) },
detached = true,
}, function(code)
stdout:close()
stderr:close()
handle:close()
if code ~= 0 then
vim.schedule(function()
lazy_util.warn(string.format('Delve exited with exit code: %d', code), { title = '[go] DAP Warning' })
end)
end
end)
assert(handle, string.format('Error running delve: %s', pid_or_err))
stdout:read_start(on_read)
stderr:read_start(on_read)
-- Wait for delve to start
vim.defer_fn(function()
callback { type = 'server', host = host, port = port }
end, 1000)
end
dap.configurations.go = {
{
name = 'Attach',
mode = 'local',
type = 'go',
request = 'attach',
processId = require('dap.utils').pick_process,
},
-- TODO: test this remote attach setup with Bazel
-- Ref:
-- - https://github.com/bazelbuild/rules_go/issues/1844#issuecomment-1281231804
-- - https://github.com/golang/vscode-go/wiki/debugging#remote-debugging
{
name = 'Attach (remote)',
mode = 'remote',
type = 'go',
request = 'attach',
connect = get_connection,
},
{
name = 'Debug',
type = 'go',
request = 'launch',
program = '${file}',
},
{
name = 'Debug (arguments)',
type = 'go',
request = 'launch',
program = '${file}',
args = get_arguments,
},
{
name = 'Debug test',
type = 'go',
request = 'launch',
mode = 'test',
program = '${file}',
},
{
name = 'Debug test (go.mod)',
type = 'go',
request = 'launch',
mode = 'test',
program = './${relativeFileDirname}',
},
}

View File

@ -0,0 +1,19 @@
local vars = require('user.config.vars')
for name, sign in pairs(vars.icons.dap) do
sign = type(sign) == 'table' and sign or { sign }
vim.fn.sign_define('Dap' .. name, {
text = sign[1],
texthl = sign[2] or 'DiagnosticInfo',
linehl = sign[3],
numhl = sign[3],
})
end
require('user.plugins.debugger.dap.dlv')
require('user.plugins.debugger.dap.debugpy')
-- Use overseer's JSON decoder
require('dap.ext.vscode').json_decode = require('overseer.json').decode
-- Then enable the integration manually
require('overseer').patch_dap(true)

View File

@ -0,0 +1,138 @@
return {
{
'rcarriga/nvim-dap-ui',
keys = {
{ '<leader>du', function() require('dapui').toggle() end, desc = 'Dap UI' },
{ '<leader>de', function() require('dapui').eval() end, desc = 'Eval', mode = { 'n', 'v' } },
},
dependencies = {
{ 'theHamsta/nvim-dap-virtual-text', config = true },
{
'mfussenegger/nvim-dap',
keys = {
{ '<leader>dB', function() require('dap').set_breakpoint(vim.fn.input('Breakpoint condition: ')) end, desc = 'Breakpoint condition' },
{ '<leader>db', function() require('dap').toggle_breakpoint() end, desc = 'Toggle breakpoint' },
{ '<leader>dc', function() require('dap').continue() end, desc = 'Continue' },
{ '<leader>dC', function() require('dap').run_to_cursor() end, desc = 'Run to cursor' },
{ '<leader>dg', function() require('dap').goto_() end, desc = 'Go to line (skipped)' },
{ '<leader>di', function() require('dap').step_into() end, desc = 'Step into' },
{ '<leader>dj', function() require('dap').down() end, desc = 'Down' },
{ '<leader>dk', function() require('dap').up() end, desc = 'Up' },
{ '<leader>dl', function() require('dap').run_last() end, desc = 'Run last' },
{ '<leader>do', function() require('dap').step_out() end, desc = 'Step out' },
{ '<leader>dO', function() require('dap').step_over() end, desc = 'Step over' },
{ '<leader>dp', function() require('dap').pause() end, desc = 'Pause' },
{ '<leader>dr', function() require('dap').repl.toggle() end, desc = 'Toggle REPL' },
{ '<leader>ds', function() require('dap').session() end, desc = 'Session' },
{ '<leader>dt', function() require('dap').terminate() end, desc = 'Terminate' },
{ '<leader>dw', function() require('dap.ui.widgets').hover() end, desc = 'Widgets' },
},
config = function()
require('user.plugins.debugger.dap')
end,
},
},
opts = {
floating = { border = require('user.config.vars').border },
},
config = function(_, opts)
local dap, dapui = require('dap'), require('dapui')
dapui.setup(opts)
dap.listeners.after.event_initialized['dapui_config'] = function()
dapui.open()
end
dap.listeners.before.event_terminated['dapui_config'] = function()
dapui.close()
end
dap.listeners.before.event_exited['dapui_config'] = function()
dapui.close()
end
end,
},
{
'nvim-neotest/neotest',
dependencies = {
'lawrence-laz/neotest-zig',
'marilari88/neotest-vitest',
'nvim-neotest/neotest-jest',
'nvim-neotest/neotest-go',
'nvim-neotest/neotest-python',
},
keys = {
{
'<leader>tt',
function()
local actions = {
['Single position'] = function()
require('neotest').run.run()
end,
['Current file'] = function()
require('neotest').run.run(vim.api.nvim_buf_get_name(0))
end,
['Directory'] = function()
vim.ui.input({
prompt = 'Path: ',
default = vim.fn.getcwd(),
completion = 'file',
}, function(path)
if path then
require('neotest').run.run(path)
end
end)
end,
['Nearest debug'] = function()
require('neotest').run.run { strategy = 'dap' }
end,
['Rerun last position'] = function()
require('neotest').run.run_last()
end,
['All adapters'] = function()
for _, adapter_id in ipairs(require('neotest').state.adapter_ids()) do
require('neotest').run.run { suite = true, adapter = adapter_id }
end
end,
}
vim.ui.select(vim.tbl_keys(actions), { prompt = 'Run test option' }, function(choice)
if choice then actions[choice]() end
end)
end,
desc = 'Run test',
},
{ '<leader>ts', function() require('neotest').run.stop() end, desc = 'Stop test' },
{ '<leader>ta', function() require('neotest').run.attach() end, desc = 'Attach to test' },
{ '<leader>ty', function() require('neotest').summary.toggle() end, desc = 'Toggle test summary' },
{ '<leader>to', function() require('neotest').output.open { enter = true, auto_close = true } end, desc = 'Show test output' },
{ '<leader>tO', function() require('neotest').output_panel.toggle() end, desc = 'Toggle test panel' },
},
config = function()
require('user.plugins.debugger.neotest')
end,
},
{
'andythigpen/nvim-coverage',
cmd = { 'Coverage', 'CoverageLoad', 'CoverageClear', 'CoverageSummary' },
keys = {
{
'<leader>tc',
function()
local actions = {
['Load coverage'] = function() require('coverage').load(true) end,
['Toggle signs'] = function() require('coverage').toggle() end,
['Clear coverage cache'] = function() require('coverage').clear() end,
['Show summary report'] = function() require('coverage').summary() end,
}
vim.ui.select(vim.tbl_keys(actions), { prompt = 'Coverage action' }, function(choice)
if choice then actions[choice]() end
end)
end,
desc = 'Coverage',
}
},
opts = function()
return require('user.plugins.debugger.coverage')
end,
},
}

View File

@ -0,0 +1,44 @@
local neotest_ns = vim.api.nvim_create_namespace('neotest')
vim.diagnostic.config({
virtual_text = {
format = function(diagnostic)
local message = diagnostic.message:gsub('\n', ' '):gsub('\t', ' '):gsub('%s+', ' '):gsub('^%s+', '')
return message
end,
},
virtual_lines = false,
}, neotest_ns)
require('neotest').setup {
adapters = {
require('neotest-go'), -- TODO: https://github.com/nvim-neotest/neotest-go/issues/57 (generate coverage file)
require('neotest-jest') { cwd = require('neotest-jest').root },
require('neotest-python'),
require('neotest-vitest'),
require('neotest-zig'),
},
consumers = {
overseer = require('neotest.consumers.overseer'),
},
discovery = { enabled = false },
floating = {
border = require('user.config.vars').border,
max_height = 0.8,
max_width = 0.8,
},
icons = {
child_indent = '',
child_prefix = '',
collapsed = '',
expanded = '',
failed = '',
final_child_indent = ' ',
final_child_prefix = '',
non_collapsible = '',
passed = '',
running = '',
running_animated = { '/', '|', '\\', '-', '/', '|', '\\', '-' },
skipped = '󰒬',
unknown = ''
},
}

View File

@ -0,0 +1,23 @@
local options = {
headline_highlights = {
'Headline1',
'Headline2',
'Headline3',
'Headline4',
'Headline5',
'Headline6',
},
codeblock_highlight = 'CodeBlock',
dash_highlight = 'Dash',
dash_string = '-',
quote_highlight = 'Quote',
quote_string = '',
fat_headlines = false,
fat_headline_upper_string = '',
fat_headline_lower_string = '🬂',
}
return {
markdown = options,
org = options,
}

View File

@ -0,0 +1,34 @@
return {
indent = { char = '', tab_char = '' },
scope = {
show_start = false,
show_end = false,
include = { node_type = { ['*'] = { '*' } } },
},
exclude = {
filetypes = {
'alpha',
'lazy',
'log',
'notify',
'undotree',
'Trouble',
'NvimTree',
'diff',
'qf',
'help',
'prompt',
'noice',
'aerial',
'TelescopePrompt',
'Trouble',
'OverseerForm',
'gitcommit',
'markdown',
'org',
'json',
'txt',
'', -- for all buffers without a filetype
},
},
}

View File

@ -0,0 +1,380 @@
local ts_parsers_path = require('user.config.vars').ts_parsers_path
return {
{ 'MTDL9/vim-log-highlighting', ft = 'log' },
{
'nvim-orgmode/orgmode',
ft = 'org',
config = function()
require('user.plugins.editor.orgmode')
end,
},
{
'lukas-reineke/headlines.nvim',
ft = { 'org', 'markdown' },
opts = require('user.plugins.editor.headlines'),
config = function(_, opts)
-- NOTE: lazily starting up headlines.nvim to prevent it from slowing down on file opening
vim.schedule(function()
require('headlines').setup(opts)
require('headlines').refresh()
end)
end,
},
{
'folke/todo-comments.nvim',
cmd = { 'TodoTrouble', 'TodoTelescope' },
event = { 'BufReadPost', 'BufNewFile' },
keys = {
{ ']t', function() require('todo-comments').jump_next() end, desc = 'Next todo comment' },
{ '[t', function() require('todo-comments').jump_prev() end, desc = 'Previous todo comment' },
{ 'gt', '<cmd>TodoTrouble<CR>', desc = 'Todo items' },
{ '<leader>ft', '<cmd>TodoTelescope<CR>', desc = 'Todo items' },
},
opts = require('user.plugins.editor.todo-comments'),
},
{
'nvim-treesitter/nvim-treesitter',
build = { '/bin/mkdir -p ' .. ts_parsers_path, ':TSUpdate' },
event = { 'BufReadPost', 'BufNewFile' },
keys = {
{ '<C-Space>', desc = 'Increment selection' },
{ '<BS>', desc = 'Decrement selection', mode = 'x' },
},
dependencies = {
'HiPhish/rainbow-delimiters.nvim',
{ 'JoosepAlviste/nvim-ts-context-commentstring', opts = { enable_autocmd = false } },
{
'nvim-treesitter/nvim-treesitter-context',
keys = {
{ '[c', function() require('treesitter-context').go_to_context() end, desc = 'Go to context' },
},
},
{
'andymass/vim-matchup',
init = function()
vim.g.matchup_matchparen_offscreen = { method = 'popup' }
end,
},
},
init = function(plugin)
vim.opt.rtp:append(ts_parsers_path)
-- Make queries available early, since lots of plugins don't require nvim-treesitter anymore
require('lazy.core.loader').add_to_rtp(plugin)
require('nvim-treesitter.query_predicates')
end,
opts = require('user.plugins.editor.treesitter'),
config = function(_, opts)
require('nvim-treesitter.configs').setup(opts)
-- tree-sitter based folding
vim.opt.foldmethod = 'expr'
vim.opt.foldexpr = 'nvim_treesitter#foldexpr()'
end,
},
{
'windwp/nvim-ts-autotag',
ft = {
'html',
'javascript',
'typescript',
'javascriptreact',
'typescriptreact',
'vue',
'xml',
'php',
'markdown',
'svelte',
'rescript',
'glimmer',
'astro',
'html.handlebars',
},
},
{
'lukas-reineke/indent-blankline.nvim',
event = { 'BufReadPost', 'BufNewFile' },
main = 'ibl',
opts = require('user.plugins.editor.indent-blankline'),
},
{
'mizlan/iswap.nvim',
cmd = { 'ISwapWith', 'ISwap' },
keys = {
{ '<leader>es', '<cmd>ISwapWith<CR>', desc = 'Swap arguments' },
},
opts = { hl_grey = 'LineNr', autoswap = true },
},
{
'danymat/neogen',
cmd = 'Neogen',
keys = {
{ '<leader>eg', function() require('neogen').generate() end, desc = 'Generate annotation' },
-- { '<C-l>', function() require('neogen').jump_next() end, desc = 'Next annotation', mode = 'i' },
-- { '<C-h>', function() require('neogen').jump_prev() end, desc = 'Previous annotation', mode = 'i' },
},
opts = {
enabled = true,
input_after_comment = true,
snippet_engine = 'luasnip',
},
},
{
'folke/zen-mode.nvim',
cmd = 'ZenMode',
keys = {
{ '<leader>ez', '<cmd>ZenMode', desc = 'Zen mode' },
},
dependencies = {
{
'folke/twilight.nvim',
cmd = { 'Twilight', 'TwilightEnable' },
opts = require('user.plugins.editor.twilight'),
},
},
opts = { window = { width = 150 } },
},
{
'monaqa/dial.nvim',
keys = {
{ '<C-a>', function() return require('dial.map').inc_normal() end, expr = true, desc = 'Increment' },
{ '<C-x>', function() return require('dial.map').dec_normal() end, expr = true, desc = 'Decrement' },
{ '<C-a>', function() return require('dial.map').inc_visual() end, expr = true, desc = 'Increment', mode = 'x' },
{ '<C-x>', function() return require('dial.map').dec_visual() end, expr = true, desc = 'Decrement', mode = 'x' },
{ 'g<C-a>', function() return require('dial.map').inc_gvisual() end, expr = true, desc = 'Increment (multiline)', mode = 'x' },
{ 'g<C-x>', function() return require('dial.map').dec_gvisual() end, expr = true, desc = 'Decrement (multiline)', mode = 'x' },
},
config = function()
local augend = require('dial.augend')
require('dial.config').augends:register_group {
default = {
augend.integer.alias.decimal_int,
augend.integer.alias.hex,
augend.constant.alias.bool,
augend.constant.new { elements = { 'True', 'False' }, word = true, cyclic = true },
augend.hexcolor.new { case = 'lower' },
augend.semver.alias.semver,
augend.date.alias['%Y/%m/%d'],
},
}
end,
},
{
'max397574/better-escape.nvim',
event = 'InsertCharPre',
opts = {
mapping = { 'jk', 'kj' },
timeout = vim.opt.timeoutlen:get(),
clear_empty_lines = false,
keys = '<Esc>',
},
},
{
'eraserhd/parinfer-rust',
build = 'cargo build --locked --release',
ft = {
'clojure',
'lisp',
'scheme',
'fennel',
'racket',
'hy',
'janet',
'carp',
'wast',
},
},
{
'jbyuki/venn.nvim',
cmd = 'VBox',
keys = {
{
'<leader>ev', function()
local venn_enabled = vim.inspect(vim.b.venn_enabled)
local key_opts = { noremap = true, silent = true, buffer = true }
local lazy_util = require('lazy.core.util')
if venn_enabled == 'nil' then
vim.b.venn_enabled = true
vim.opt_local.virtualedit = 'all'
-- Draw lines with WASD keystroke
vim.keymap.set('n', 'A', '<C-v>h:VBox<CR>', key_opts)
vim.keymap.set('n', 'A', '<C-v>h:VBox<CR>', key_opts)
vim.keymap.set('n', 'S', '<C-v>j:VBox<CR>', key_opts)
vim.keymap.set('n', 'W', '<C-v>k:VBox<CR>', key_opts)
vim.keymap.set('n', 'D', '<C-v>l:VBox<CR>', key_opts)
-- Draw boxes by pressing 'f' with visual selection
vim.keymap.set('x', 'f', ':VBox<CR>', key_opts)
lazy_util.info('Virtual box editing mode enabled.', { title = 'Venv mode', icon = '' })
else
vim.b.venn_enabled = nil
vim.opt_local.virtualedit = vim.opt.virtualedit:get()
vim.keymap.del('n', 'A', { buffer = true })
vim.keymap.del('n', 'S', { buffer = true })
vim.keymap.del('n', 'W', { buffer = true })
vim.keymap.del('n', 'D', { buffer = true })
vim.keymap.del('x', 'f', { buffer = true })
lazy_util.info('Virtual box editing mode disabled.', { title = 'Venv mode', icon = '' })
end
end,
desc = 'Virtual box edit',
},
},
},
{
'folke/flash.nvim',
keys = {
{ '-', function() require('flash').jump() end, mode = { 'n', 'x', 'o' }, desc = 'Flash' },
{ '_', function() require('flash').treesitter() end, mode = { 'n', 'x', 'o' }, desc = 'Flash (Treesitter)' },
{ 'gs', function() require('flash').remote() end, mode = 'o', desc = 'Flash (remote)' },
{ 'gS', function() require('flash').treesitter_search() end, mode = { 'x', 'o' }, desc = 'Flash search (Treesitter)' },
{ '<C-s>', function() require('flash').toggle() end, mode = 'c', desc = 'Toggle Flash search' },
'f', 'F', 't', 'T',
},
opts = {
search = { incremental = true },
label = { after = false, before = true },
modes = {
search = { enabled = false },
char = { jump_labels = true, multi_line = false },
},
prompt = { enabled = false },
},
},
{
'Wansmer/treesj',
keys = {
{ 'gJ', '<cmd>TSJToggle<CR>', desc = 'Join toggle' },
},
opts = { use_default_keymaps = false, max_join_length = 150 },
},
{
'echasnovski/mini.move',
keys = {
{ '<A-h>', mode = { 'n', 'x' }, desc = 'Move left' },
{ '<A-j>', mode = { 'n', 'x' }, desc = 'Move down' },
{ '<A-k>', mode = { 'n', 'x' }, desc = 'Move up' },
{ '<A-l>', mode = { 'n', 'x' }, desc = 'Move right' },
},
opts = {
options = {
reindent_linewise = true,
},
},
config = function(_, opts)
require('mini.move').setup(opts)
end,
},
{
'echasnovski/mini.ai',
event = 'VeryLazy',
dependencies = {
{
'nvim-treesitter/nvim-treesitter-textobjects',
-- we only need the queries, other functions aren't used
init = function()
require('lazy.core.loader').disable_rtp_plugin('nvim-treesitter-textobjects')
end,
},
},
config = function()
require('user.plugins.editor.mini-ai')
end,
},
{
'echasnovski/mini.pairs',
event = 'InsertEnter',
config = function()
require('mini.pairs').setup()
end,
},
{
'echasnovski/mini.align',
keys = function(_, keys)
local plugin = require('lazy.core.config').spec.plugins['mini.align']
local opts = require('lazy.core.plugin').values(plugin, 'opts', false)
local mappings = {
{ opts.mappings.start, mode = { 'n', 'v' }, desc = 'Align text' },
{ opts.mappings.start_with_preview, mode = { 'n', 'v' }, desc = 'Align text (with preview)' },
}
mappings = vim.tbl_filter(function(m)
return m[1] and #m[1] > 0
end, mappings)
return vim.list_extend(mappings, keys)
end,
opts = { mappings = { start = 'ga', start_with_preview = 'gA' } },
config = function(_, opts)
require('mini.align').setup(opts)
end,
},
{
'echasnovski/mini.comment',
keys = {
{ 'gc', mode = 'o' },
{ 'gc', mode = { 'n', 'x' }, desc = 'Toggle comment' },
{ 'gcc', mode = 'n', desc = 'Toggle comment on current line' },
},
opts = {
options = {
ignore_blank_line = true,
custom_commentstring = function()
return require('ts_context_commentstring.internal').calculate_commentstring() or vim.bo.commentstring
end,
},
},
config = function(_, opts)
require('mini.comment').setup(opts)
end,
},
{
'echasnovski/mini.surround',
keys = function(_, keys)
local plugin = require('lazy.core.config').spec.plugins['mini.surround']
local opts = require('lazy.core.plugin').values(plugin, 'opts', false)
local mappings = {
{ opts.mappings.add, mode = { 'n', 'x' }, desc = 'Add surrounding' },
{ opts.mappings.delete, desc = 'Delete surrounding' },
{ opts.mappings.find, desc = 'Find surrounding' },
{ opts.mappings.find_left, desc = 'Find left surrounding' },
{ opts.mappings.highlight, desc = 'Highlight surrounding' },
{ opts.mappings.replace, desc = 'Replace surrounding' },
{ opts.mappings.update_n_lines, desc = 'Update `MiniSurround.config.n_lines`' },
}
mappings = vim.tbl_filter(function(m)
return m[1] and #m[1] > 0
end, mappings)
return vim.list_extend(mappings, keys)
end,
opts = {
mappings = {
add = 'sa',
delete = 'sd',
find = 'sf',
find_left = 'sF',
highlight = 'sh',
replace = 'sr',
update_n_lines = 'sn',
},
silent = true,
search_method = 'cover_or_next',
highlight_duration = vim.opt.timeoutlen:get(),
},
config = function(_, opts)
require('mini.surround').setup(opts)
end,
},
{
'echasnovski/mini.animate',
event = 'VeryLazy',
opts = function()
return require('user.plugins.editor.mini-animate')
end,
config = function(_, opts)
require('mini.animate').setup(opts)
end,
},
}

View File

@ -0,0 +1,17 @@
local ai = require('mini.ai')
ai.setup {
silent = true,
-- https://github.com/echasnovski/mini.nvim/issues/122
n_lines = 500,
-- Text objects from nvim-treesitter-textobjects
custom_textobjects = {
o = ai.gen_spec.treesitter({
a = { '@block.outer', '@conditional.outer', '@loop.outer' },
i = { '@block.inner', '@conditional.inner', '@loop.inner' },
}),
f = ai.gen_spec.treesitter({ a = '@function.outer', i = '@function.inner' }),
c = ai.gen_spec.treesitter({ a = '@class.outer', i = '@class.inner' }),
t = { '<([%p%w]-)%f[^<%w][^<>]->.-</%1>', '^<.->().*()</[^/]->$' },
},
}

View File

@ -0,0 +1,33 @@
-- Don't use animate when scrolling with the mouse
local mouse_scrolled = false
for _, scroll in ipairs({ 'Up', 'Down' }) do
local key = '<ScrollWheel' .. scroll .. '>'
vim.keymap.set({ 'n', 'i' }, key, function()
mouse_scrolled = true
return key
end, { expr = true })
end
local updatetime = vim.opt.updatetime:get()
local animate = require('mini.animate')
return {
cursor = {
path = animate.gen_path.line(),
timing = animate.gen_timing.linear { duration = updatetime, unit = 'total' },
},
resize = { timing = animate.gen_timing.linear { duration = updatetime, unit = 'total' }, },
scroll = {
timing = animate.gen_timing.linear { duration = updatetime, unit = 'total' },
subscroll = animate.gen_subscroll.equal {
predicate = function(total_scroll)
if mouse_scrolled then
mouse_scrolled = false
return false
end
return total_scroll > 1
end,
},
},
open = { enable = false },
close = { enable = false },
}

View File

@ -0,0 +1,75 @@
local c = require('user.themes.' .. vim.g.colors_name .. '.colors')
local keyword_faces = {
TODO = ':foreground ' .. c.green .. ' :weight bold',
WAIT = ':foreground ' .. c.yellow .. ' :weight bold',
HOLD = ':foreground ' .. c.yellow .. ' :weight bold',
IDEA = ':foreground ' .. c.cyan .. ' :weight bold :slant italic',
DONE = ':foreground ' .. c.grey_bright .. ' :weight bold',
OKAY = ':foreground ' .. c.purple .. ' :weight bold :slant italic',
KILL = ':foreground ' .. c.red .. ' :weight bold',
CANCELED = ':foreground ' .. c.red .. ' :weight bold',
YES = ':foreground ' .. c.green .. ' :weight bold :underline on',
NO = ':foreground ' .. c.red .. ' :weight bold :underline on',
}
local keywords = {}
for k, _ in pairs(keyword_faces) do
table.insert(keywords, k)
end
require('orgmode').setup_ts_grammar()
require('orgmode').setup {
-- General settings
org_agenda_files = { '~/Documents/Org/agenda/*' },
org_default_notes_file = '~/Documents/Org/notes.org',
org_todo_keywords = keywords,
org_todo_keyword_faces = keyword_faces,
org_hide_emphasis_markers = true,
org_highlight_latex_and_related = 'entities',
-- Agenda settings
org_deadline_warning_days = 7,
org_agenda_span = 'week',
org_agenda_start_on_weekday = 7, -- Start a week in Sunday
org_agenda_min_height = 15,
-- Tags settings
org_use_tag_inheritance = false,
-- Other stuff
win_border = require('user.config.vars').border,
-- Notifications
notifications = {
enabled = true,
cron_enabled = false,
repeater_reminder_time = false,
deadline_warning_reminder_time = false,
reminder_time = { 0, 5, 10 },
deadline_reminder = true,
scheduled_reminder = true,
notifier = function(tasks)
for _, task in ipairs(tasks) do
local task_type = string.format('%s: <%s>', task.type, task.time:to_string())
local task_description = string.format('%s %s %s', string.rep('*', task.level), task.todo, task.title)
require('lazy.core.util').info(string.format('%s\n%s', task_description, task_type), {
title = { task.category, task.humanized_duration },
icon = '󱣹 ',
on_open = function(win)
local buf = vim.api.nvim_win_get_buf(win)
vim.api.nvim_buf_set_option(buf, 'filetype', 'org')
end,
})
end
end,
},
}
require('which-key').register {
['<leader>o'] = {
name = 'Org',
i = { name = 'Insert' },
x = { name = 'Clock' },
},
}

View File

@ -0,0 +1,32 @@
return {
signs = false,
keywords = {
FIX = { icon = '', color = 'error', alt = { 'FIXME', 'BUG', 'FIXIT', 'ISSUE' } },
TODO = { icon = '', color = 'info' },
HACK = { icon = '', color = 'warning' },
WARN = { icon = '', color = 'warning', alt = { 'WARNING', 'XXX' } },
PERF = { icon = '󰓅 ', alt = { 'OPTIM', 'PERFORMANCE', 'OPTIMIZE' } },
NOTE = { icon = '', color = 'hint', alt = { 'INFO' } },
},
merge_keywords = true,
gui_style = { fg = 'BOLD', bg = 'NONE' },
highlight = {
before = '',
keyword = 'fg',
after = '',
comments_only = true,
exclude = { 'org' },
},
colors = {
error = { 'DiagnosticError', '@text.danger' },
warning = { 'DiagnosticWarn', '@text.warning' },
info = { 'DiagnosticInfo', '@text.note' },
hint = { 'DiagnosticHint' },
default = { 'Normal' },
test = { 'Identifier' },
},
search = {
command = 'rg',
args = require('user.config.vars').rg_args,
},
}

View File

@ -0,0 +1,37 @@
return {
parser_install_dir = require('user.config.vars').ts_parsers_path,
ensure_installed = 'all',
sync_install = false,
auto_install = false,
highlight = {
enable = true,
additional_vim_regex_highlighting = { 'org' },
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = '<C-Space>',
node_incremental = '<C-Space>',
scope_incremental = '<nop>',
node_decremental = '<BS>',
},
},
indent = { enable = false },
autotag = {
enable = true,
filetypes = {
'html',
'javascript',
'javascriptreact',
'typescript',
'typescriptreact',
'svelte',
'vue',
},
},
matchup = {
enable = true,
disable_virtual_text = true,
include_match_words = true,
},
}

View File

@ -0,0 +1,29 @@
return {
dimming = {
alpha = 0.25,
color = { 'Normal', '#ffffff' },
inactive = false,
},
context = 10,
treesitter = true,
expand = {
'function',
'method',
'table',
'if_statement',
},
exclude = {
'alpha',
'lazy',
'aerial',
'OverseerForm',
'TelescopePrompt',
'notify',
'undotree',
'Trouble',
'NvimTree',
'diff',
'qf',
'help',
},
}

10
lua/user/plugins/init.lua Normal file
View File

@ -0,0 +1,10 @@
return {
-- lazy.nvim can manage itself
{ 'folke/lazy.nvim', version = '*' },
-- dependencies needed by the other
'MunifTanjim/nui.nvim',
'nvim-lua/plenary.nvim',
'nvim-tree/nvim-web-devicons',
{ 'tpope/vim-repeat', event = { 'BufNewFile', 'BufReadPost' } },
}

View File

@ -0,0 +1,27 @@
local vars = require('user.config.vars')
local icons = {}
for name, val in pairs(vars.icons.kind) do
if val.hl ~= nil then
icons[name] = val.icon .. ' '
vim.api.nvim_set_hl(0, 'Aerial' .. name .. 'Icon', { link = val.hl })
end
end
icons['Collapsed'] = ''
return {
backends = { 'lsp', 'treesitter', 'markdown', 'man' },
layout = { width = 30 },
show_guides = true,
highlight_on_hover = true,
icons = icons,
filter_kind = false,
float = { border = vars.border, relative = 'editor' },
nav = {
border = vars.border,
preview = true,
max_width = 0.8,
win_opts = { winblend = 0 },
keymaps = { ['q'] = 'actions.close' },
},
}

View File

@ -0,0 +1,13 @@
local linters_path = vim.fn.stdpath('data') .. '/lint'
local util = require('user.util.misc')
return {
buf = { filetypes = 'proto' },
fish_indent = { filetypes = 'fish' },
-- goimports = { filetypes = 'go', condition = util.root_has_file({ '.git', 'go.mod', 'go.work' }) },
shfmt = { filetypes = 'sh' },
sql_formatter = { filetypes = 'sql', cmd = linters_path .. '/sql_formatter/node_modules/.bin/sql-formatter' },
stylua = { filetypes = 'lua', condition = util.root_has_file({ 'stylua.toml', '.stylua.toml' }) },
templ = { filetypes = 'templ' },
yamlfmt = { filetypes = { 'yaml', 'yaml.ansible' } },
}

View File

@ -0,0 +1,117 @@
return {
{
'neovim/nvim-lspconfig',
event = { 'BufReadPost', 'BufNewFile' },
dependencies = {
'b0o/SchemaStore.nvim',
{ 'folke/neoconf.nvim', cmd = 'Neoconf', config = true },
{ 'https://git.sr.ht/~whynothugo/lsp_lines.nvim', config = true },
{
'SmiteshP/nvim-navic',
config = function()
require('user.plugins.lsp.navic')
end,
},
},
config = function()
require('user.plugins.lsp.lspconfig')
end,
},
{
'mfussenegger/nvim-lint',
event = { 'BufReadPost', 'BufNewFile', 'BufWritePre' },
opts = function() return require('user.plugins.lsp.lint') end,
config = function(_, opts)
local lint = require('lint')
local function debounce(ms, fn)
local timer = vim.loop.new_timer()
return function(...)
local argv = { ... }
timer:start(ms, 0, function()
timer:stop()
vim.schedule_wrap(fn)(unpack(argv))
end)
end
end
-- Linters are invoked explicitly, so don't need to define `lint.linters_by_ft`
local function try_lint()
local ft = vim.bo.filetype
local names = lint._resolve_linter_by_ft(ft)
local additional_linters = { fallback = {}, global = {} }
for name, conf in pairs(opts) do
local enabled_ft = type(conf.filetypes) == 'table' and conf.filetypes or { conf.filetypes }
if vim.tbl_contains(enabled_ft, ft) then
vim.list_extend(names, { name } or {})
end
-- * and _ is treated like in `conform.nvim` (assume they are defined as the 1st table element)
if enabled_ft[1] == '_' then
vim.list_extend(additional_linters.fallback, { name } or {})
end
if enabled_ft[1] == '*' then
vim.list_extend(additional_linters.global, { name } or {})
end
end
-- Add fallback and global linters
if #names == 0 then
vim.list_extend(names, additional_linters.fallback or {})
end
vim.list_extend(names, additional_linters.global or {})
-- Filter out linters that don't exist or don't match the defined condition
local file = vim.api.nvim_buf_get_name(0)
names = vim.tbl_filter(function(name)
local conf = opts[name]
return conf and not (type(conf) == 'table' and conf.condition and not conf.condition(file))
end, names)
-- Run linters
if #names > 0 then
lint.try_lint(names)
end
end
-- Add custom linter configurations to the plugin's configuration
for name, conf in pairs(opts) do
if type(conf) == 'table' and type(lint.linters[name]) == 'table' then
lint.linters[name] = vim.tbl_deep_extend('force', lint.linters[name], conf)
else
lint.linters[name] = conf
end
-- Remove our custom fields
lint.linters[name].filetypes = nil
lint.linters[name].condition = nil
end
vim.api.nvim_create_autocmd({ 'BufWritePost', 'BufReadPost', 'InsertLeave' }, {
group = vim.api.nvim_create_augroup('nvim-lint', { clear = true }),
callback = debounce(100, try_lint),
})
end,
},
{
'stevearc/conform.nvim',
cmd = 'ConformInfo',
keys = {},
opts = function() return require('user.plugins.lsp.conform') end,
config = function(_, opts)
end,
},
{ 'smjonas/inc-rename.nvim', cmd = 'IncRename', opts = { hl_group = 'IncSearch' } },
{
'stevearc/aerial.nvim',
keys = {
{ '<leader>lg', '<cmd>AerialToggle<CR>', desc = 'Symbols' },
{ '<leader>lG', '<cmd>AerialNavToggle<CR>', desc = 'Symbols (Nav)' },
},
cmd = { 'AerialToggle', 'AerialNavToggle' },
opts = function()
return require('user.plugins.lsp.aerial')
end,
},
}

View File

@ -0,0 +1,29 @@
local linters_path = vim.fn.stdpath('data') .. '/lint'
local util = require('user.util.misc')
-- `condition` and `filetypes` are custom fields.
-- The other is the same as in `require('lint').linters.<linter_name>`
return {
buf = { filetypes = 'proto' },
buildifier = { filetypes = 'bzl' },
-- codespell = { filetypes = '*', cmd = linters_path .. '/codespell/bin/codespell' },
cspell = {
cmd = linters_path .. '/cspell/node_modules/.bin/cspell',
filetypes = '*',
condition = util.root_has_file({
'.cspell.json',
'cspell.json',
'.cSpell.json',
'cSpell.json',
'cspell.config.json',
}),
},
fish = { filetypes = 'fish', args = { '--private', '--no-execute' } },
-- hadolint = { filetypes = 'dockerfile' },
-- proselint = { filetypes = { 'markdown', 'asciidoc', 'org' }, cmd = linters_path .. '/proselint/bin/proselint' },
selene = { filetypes = 'lua', condition = util.root_has_file('selene.toml') },
sqlfluff = { filetypes = 'sql', cmd = linters_path .. '/sqlfluff/bin/sqlfluff' },
tflint = { filetypes = 'terraform', condition = util.root_has_file('.tflint.hcl') },
tfsec = { filetypes = 'terraform' },
vale = { filetypes = 'markdown', condition = util.root_has_file('.vale.ini') },
}

View File

@ -0,0 +1,90 @@
local M = {}
local lazy_util = require('lazy.core.util')
local vars = require('user.config.vars')
-- TODO: nvim-0.10.0 can have different virtual_text prefix per severity
local function set_virtual_text()
if vars.lsp_virtual_lines then
return false
end
return { prefix = '', spacing = 2, source = 'if_many' }
end
function M.configure_diagnostic()
vim.diagnostic.config {
virtual_text = set_virtual_text(),
virtual_lines = vars.lsp_virtual_lines,
severity_sort = true,
float = {
border = vars.border,
prefix = function(diag)
local level = vim.diagnostic.severity[diag.severity]
local prefix = string.format('%s ', vars.icons.notify[level:lower()])
return prefix, 'Diagnostic' .. level:gsub('^%l', string.upper)
end,
},
}
-- lsp_lines is annoying in LazyUI, so always disable it there
vim.diagnostic.config({ virtual_lines = false }, require('lazy.core.config').ns)
-- :help diagnostic-handlers-example
-- Display only 1 sign from the highest severity
local ns = vim.api.nvim_create_namespace('customDiagnosticSign_ns')
local orig_signs_handler = vim.diagnostic.handlers.signs
vim.diagnostic.handlers.signs = {
show = function(_, bufnr, _, opts)
local diagnostics = vim.diagnostic.get(bufnr)
local max_severity_per_line = {}
for _, d in pairs(diagnostics) do
local m = max_severity_per_line[d.lnum]
if not m or d.severity < m.severity then
max_severity_per_line[d.lnum] = d
end
end
local filtered_diagnostics = vim.tbl_values(max_severity_per_line)
orig_signs_handler.show(ns, bufnr, filtered_diagnostics, opts)
end,
hide = function(_, bufnr)
orig_signs_handler.hide(ns, bufnr)
end,
}
-- Set diagnostic sign icons
for _, name in ipairs { 'error', 'warn', 'hint', 'info' } do
local icon = vars.icons.notify[name]
local hl = 'DiagnosticSign' .. name:gsub('^%l', string.upper)
vim.fn.sign_define(hl, { text = icon, texthl = hl })
end
end
function M.toggle_virtual_lines()
vars.lsp_virtual_lines = not vars.lsp_virtual_lines
-- Configure diagnostic again for the new settings
vim.diagnostic.config {
virtual_text = set_virtual_text(),
virtual_lines = vars.lsp_virtual_lines
}
if vars.lsp_virtual_lines then
lazy_util.info('Virtual lines enabled', { title = 'Diagnostic' })
else
lazy_util.info('Virtual lines disabled', { title = 'Diagnostic' })
end
end
local diagnostic_enabled = true
function M.toggle()
diagnostic_enabled = not diagnostic_enabled
if diagnostic_enabled then
vim.diagnostic.enable()
lazy_util.info('LSP diagnostic enabled', { title = 'Diagnostic' })
else
vim.diagnostic.disable()
lazy_util.warn('LSP diagnostic disabled', { title = 'Diagnostic' })
end
end
return M

View File

@ -0,0 +1,41 @@
local M = {}
local lazy_util = require('lazy.core.util')
local vars = require('user.config.vars')
function M.toggle()
vars.lsp_format_on_save = not vars.lsp_format_on_save
if vars.lsp_format_on_save then
lazy_util.info('Enabled format on save', { title = 'Format' })
else
lazy_util.warn('Disabled format on save', { title = 'Format' })
end
end
function M.format()
local buf = vim.api.nvim_get_current_buf()
vim.lsp.buf.format { async = true, bufnr = buf }
end
function M.on_attach(client, buf)
if
client.config
and client.config.capabilities
and client.config.capabilities.documentFormattingProvider == false
then
return
end
if client.supports_method('textDocument/formatting') then
vim.api.nvim_create_autocmd('BufWritePre', {
group = vim.api.nvim_create_augroup('LspFormat', {}),
buffer = buf,
callback = function()
if vars.lsp_format_on_save then
M.format()
end
end,
})
end
end
return M

View File

@ -0,0 +1,80 @@
local vars = require('user.config.vars')
-- vim.lsp.set_log_level(vars.loglevel)
require('lspconfig.ui.windows').default_options.border = vars.border
require('user.plugins.lsp.lspconfig.diagnostic').configure_diagnostic()
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('UserLspConfig', {}),
callback = function(args)
local buffer = args.buf
local client = vim.lsp.get_client_by_id(args.data.client_id)
-- Formatting + Key bindings
require('user.plugins.lsp.lspconfig.format').on_attach(client, buffer)
require('user.plugins.lsp.lspconfig.keymap').on_attach(client, buffer)
-- Symbol context on winbar
if client.supports_method('textDocument/documentSymbol') then
require('nvim-navic').attach(client, buffer)
end
-- Inlay hints
local inlay_hint = vim.lsp.buf.inlay_hint or vim.lsp.inlay_hint
if vars.lsp_inlay_hints and inlay_hint then
if client.supports_method('textDocument/inlayHint') then
inlay_hint(buffer, true)
end
end
-- Bulb for code action hint in statusbar
if client.supports_method('textDocument/codeAction') then
vim.api.nvim_create_autocmd({ 'CursorHold', 'InsertLeave' }, {
group = vim.api.nvim_create_augroup('LspCodeAction', {}),
callback = require('user.util.lsp').codeAction_on_attach,
buffer = buffer,
})
end
-- Refresh codelens
if client.supports_method('textDocument/codeLens') then
vim.api.nvim_create_autocmd({ 'InsertLeave', 'BufEnter', 'CursorHold' }, {
group = vim.api.nvim_create_augroup('LspCodeLens', {}),
callback = vim.lsp.codelens.refresh,
buffer = buffer,
})
end
-- Document highlight
if vars.lsp_document_highlight and client.supports_method('textDocument/documentHighlight') then
local augroup = 'LspDocumentHighlight'
vim.api.nvim_create_augroup(augroup, {})
vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
group = augroup,
callback = vim.lsp.buf.document_highlight,
buffer = buffer,
})
vim.api.nvim_create_autocmd('CursorMoved', {
group = augroup,
callback = vim.lsp.buf.clear_references,
buffer = buffer,
})
end
-- Specific tweaks for some servers
if client.name == 'ruff_lsp' then
client.server_capabilities.hoverProvider = false
end
end,
})
local servers = require('user.plugins.lsp.lspconfig.servers')
local capabilities = require('cmp_nvim_lsp').default_capabilities(vim.lsp.protocol.make_client_capabilities())
for server, server_opts in pairs(servers) do
local opts = vim.tbl_deep_extend('force', {
capabilities = vim.deepcopy(capabilities),
}, server_opts or {})
require('lspconfig')[server].setup(opts)
end

View File

@ -0,0 +1,78 @@
local M = {}
M._keys = nil
function M.get()
local format = function()
require('user.plugins.lsp.lspconfig.format').format()
end
if not M._keys then
M._keys = {
{ '<leader>le', vim.diagnostic.open_float, desc = 'Line diagnostic' },
{ '<leader>lf', format, desc = 'Format document', has = 'documentFormatting' },
{ '<leader>lf', format, desc = 'Format range', mode = 'x', has = 'documentRangeFormatting' },
{ '<leader>la', vim.lsp.buf.code_action, desc = 'Code action', mode = { 'n', 'x' }, has = 'codeAction' },
{ '<leader>ll', vim.lsp.codelens.run, desc = 'Codelens action', mode = 'n', has = 'codeLens' },
{ '<leader>ld', '<cmd>Trouble document_diagnostics<CR>', desc = 'Document diagnostics' },
{ '<leader>lw', '<cmd>Trouble workspace_diagnostics<CR>', desc = 'Workspace diagnostics' },
{ 'gd', '<cmd>Trouble lsp_definitions<CR>', desc = 'Goto definition', has = 'definition' },
{ 'gr', '<cmd>Trouble lsp_references<CR>', desc = 'References' },
{ 'gD', vim.lsp.buf.declaration, desc = 'Goto declaration' },
{ 'gI', '<cmd>Trouble lsp_implementations<CR>', desc = 'Goto implementation' },
{ 'gy', '<cmd>Trouble lsp_type_definitions<CR>', desc = 'Goto type definition' },
{ 'K', vim.lsp.buf.hover, desc = 'Hover' },
{ 'gK', vim.lsp.buf.signature_help, desc = 'Signature help', has = 'signatureHelp' },
{ '<c-k>', vim.lsp.buf.signature_help, mode = 'i', desc = 'Signature help', has = 'signatureHelp' },
{ ']d', M.diagnostic_goto(true), desc = 'Next diagnostic' },
{ '[d', M.diagnostic_goto(false), desc = 'Previous diagnostic' },
{ ']e', M.diagnostic_goto(true, 'ERROR'), desc = 'Next error' },
{ '[e', M.diagnostic_goto(false, 'ERROR'), desc = 'Previous error' },
{ ']w', M.diagnostic_goto(true, 'WARN'), desc = 'Next warning' },
{ '[w', M.diagnostic_goto(false, 'WARN'), desc = 'Previous warning' },
}
if require('user.util.misc').has('inc-rename.nvim') then
M._keys[#M._keys + 1] = {
'<leader>lr',
function()
local inc_rename = require('inc_rename')
return ':' .. inc_rename.config.cmd_name .. ' ' .. vim.fn.expand('<cword>')
end,
expr = true,
desc = 'Rename',
has = 'rename',
}
else
M._keys[#M._keys + 1] = { '<leader>lr', vim.lsp.buf.rename, desc = 'Rename', has = 'rename' }
end
end
return M._keys
end
function M.on_attach(client, buffer)
local Keys = require('lazy.core.handler.keys')
local keymaps = Keys.resolve(M.get())
for _, keys in pairs(keymaps) do
local method = keys.has
if not keys.has or client.supports_method(method:find('/') and method or 'textDocument/' .. method) then
local opts = Keys.opts(keys)
opts.has = nil
opts.silent = opts.silent ~= false
opts.buffer = buffer
vim.keymap.set(keys.mode or 'n', keys.lhs, keys.rhs, opts)
end
end
end
function M.diagnostic_goto(next, severity)
local go = next and vim.diagnostic.goto_next or vim.diagnostic.goto_prev
severity = severity and vim.diagnostic.severity[severity] or nil
return function()
go { severity = severity }
end
end
return M

View File

@ -0,0 +1,226 @@
local servers_path = vim.fn.stdpath('data') .. '/lsp'
-- NOTE: check https://github.com/folke/neodev.nvim for more bloated library/runtime path
local function lua_lib_path()
local lib_path = {}
lib_path[os.getenv('VIMRUNTIME') .. '/lua'] = true
-- emmylua-nvim
lib_path[vim.fn.stdpath('data') .. '/lazy/emmylua-nvim'] = true
return lib_path
end
local function lua_runtime_path()
local runtime_path = {}
table.insert(runtime_path, 'lua/?.lua')
table.insert(runtime_path, 'lua/?/init.lua')
local lib_path = lua_lib_path()
for lib, _ in pairs(lib_path) do
table.insert(runtime_path, lib .. '/?.lua')
table.insert(runtime_path, lib .. '/?/init.lua')
end
return runtime_path
end
-- Read a file line by line and build a table from them
---@param file string
local function read_dict(file)
if not file then
return nil
end
local dict = {}
for line in io.lines(file) do
table.insert(dict, line)
end
return dict
end
return {
beancount = { init_options = { journalFile = os.getenv('HOME') .. '/Documents/Ledger/ledger.beancount' } },
lua_ls = {
settings = {
Lua = {
codeLens = { enable = true },
diagnostics = { globals = { 'vim', 'it', 'describe' } },
format = { enable = false },
hint = { enable = true, arrayIndex = 'Disable', setType = true },
runtime = { version = 'LuaJIT', path = lua_runtime_path() },
completion = { callSnippet = 'Replace', keywordSnippet = 'Replace' },
workspace = { checkThirdParty = false, library = lua_lib_path() },
telemetry = { enable = false },
},
},
},
-- TODO: switch to pylyzer when it is more stable
pylsp = {
cmd = { servers_path .. '/pylsp/bin/pylsp' },
settings = {
pylsp = {
plugins = {
autopep8 = { enabled = false },
pydocstyle = { enabled = true },
pylint = { enabled = true },
},
},
},
},
-- NOTE: for Bazel setup (GOPACKAGESDRIVER), use neoconf.nvim
-- Ref: https://github.com/bazelbuild/rules_go/wiki/Editor-setup
gopls = {
cmd = { 'gopls', '-remote=auto', 'serve' },
settings = {
gopls = {
gofumpt = true,
codelenses = {
gc_details = false,
generate = true,
regenerate_cgo = true,
run_govulncheck = true,
tidy = true,
upgrade_dependency = true,
vendor = true,
},
hints = {
assignVariableTypes = true,
compositeLiteralFields = true,
compositeLiteralTypes = true,
constantValues = true,
functionTypeParameters = true,
parameterNames = true,
rangeVariableTypes = true,
},
analyses = {
fieldalignment = true,
nilness = true,
shadow = true,
unusedparams = true,
unusedvariable = true,
unusedwrite = true,
useany = true,
},
usePlaceholders = true,
staticcheck = true,
vulncheck = 'Imports',
directoryFilters = {
'-.git',
'-.vscode',
'-.vscode-test',
'-.idea',
'-node_modules',
'-plz-out',
'-.plz-cache',
'-.plz-http-cache',
'-bazel-bin',
'-bazel-out',
'-bazel-testlogs',
},
},
},
},
jsonls = {
cmd = { servers_path .. '/vscode/node_modules/.bin/vscode-json-language-server', '--stdio' },
-- Schema catalog: https://www.schemastore.org/api/json/catalog.json
settings = {
json = {
schemas = require('schemastore').json.schemas(),
validate = { enable = true },
},
},
},
yamlls = {
cmd = { servers_path .. '/yamlls/node_modules/.bin/yaml-language-server', '--stdio' },
settings = {
redhat = { telemetry = { enabled = false } },
yaml = {
format = {
enable = true,
bracketSpacing = true,
printWidth = 120,
singleQuote = true,
},
validate = true,
schemas = require('schemastore').yaml.schemas(),
schemaStore = { enable = false, url = "" },
-- https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html#configure-your-ide-to-support-reference-tags
customTags = { '!reference sequence' },
},
},
},
texlab = {
settings = {
texlab = {
build = { onSave = true },
forwardSearch = {
executable = 'zathura',
args = { '--synctex-forward', '%l:1:%f', '%p' },
},
},
},
},
-- ltex = {
-- settings = {
-- ltex = {
-- dictionary = {
-- ['en-US'] = read_dict(vim.fn.stdpath('config') .. '/spell/en.utf-8.add'),
-- },
-- completionEnabled = true,
-- },
-- },
-- },
nil_ls = {
settings = {
['nil'] = {
formatting = {
command = { 'nixpkgs-fmt' },
},
},
},
},
-- volar = {
-- { cmd = { servers_path .. '/volar/node_modules/.bin/vue-language-server', '--stdio' } },
-- filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
-- on_new_config = function(config, root_dir)
-- local lsputil = require('lspconfig.util')
-- local function get_typescript_server_path(dir)
-- local global_ts = vim.fn.stdpath('data') .. '/lsp/volar/node_modules/typescript/lib'
-- local found_ts = ''
-- if lsputil.search_ancestors(dir, function(path)
-- found_ts = lsputil.path.join(path, 'node_modules', 'typescript', 'lib')
-- if lsputil.path.exists(found_ts) then return path end
-- end) then
-- return found_ts
-- end
-- return global_ts
-- end
-- config.init_options.typescript.tsdk = get_typescript_server_path(root_dir)
-- end,
-- },
ansiblels = { cmd = { servers_path .. '/ansiblels/node_modules/.bin/ansible-language-server', '--stdio' } },
bashls = { cmd = { servers_path .. '/bashls/node_modules/.bin/bash-language-server', 'start' } },
cssls = { cmd = { servers_path .. '/vscode/node_modules/.bin/vscode-css-language-server', '--stdio' } },
dockerls = { cmd = { servers_path .. '/dockerls/node_modules/.bin/docker-langserver', '--stdio' } },
emmet_language_server = { cmd = { servers_path .. '/emmet_language_server/node_modules/.bin/emmet-language-server', '--stdio' } },
html = { cmd = { servers_path .. '/vscode/node_modules/.bin/vscode-html-language-server', '--stdio' } },
-- please = { cmd = { 'build_langserver', '--mode', 'stdio' } },
ruff_lsp = { cmd = { servers_path .. '/ruff_lsp/bin/ruff-lsp' } },
sqlls = { cmd = { servers_path .. '/sqlls/node_modules/.bin/sql-language-server', 'up', '--method', 'stdio' } },
-- svelte = { cmd = { servers_path .. '/svelte/node_modules/.bin/svelteserver', '--stdio' } },
tsserver = { cmd = { servers_path .. '/tsserver/node_modules/.bin/typescript-language-server', '--stdio' } },
dhall_lsp_server = {},
gleam = {},
jsonnet_ls = {},
marksman = {},
nickel_ls = {},
-- nixd = {},
-- pylyzer = {},
qmlls = {}, -- from qt6-qtdeclarative-dev package in Alpine
regols = {},
biome = {},
taplo = {},
terraformls = {},
typst_lsp = {},
zls = {},
}

View File

@ -0,0 +1,18 @@
local lspkind_icons = require('user.config.vars').icons.kind
local navic_icons = {}
for key, val in pairs(lspkind_icons) do
if val.hl ~= nil then
navic_icons[key] = val.icon .. ' '
vim.api.nvim_set_hl(0, 'NavicIcons' .. key, { link = val.hl })
end
end
require('nvim-navic').setup {
icons = navic_icons,
highlight = true,
separator = '',
depth_limit = 0,
depth_limit_indicator = '..',
lazy_update_context = true,
}

View File

@ -0,0 +1,124 @@
local header = {
type = 'text',
val = {
[[<-. (`-')_ (`-') _ (`-') _ <-. (`-') ]],
[[ \( OO) ) ( OO).-/ .-> _(OO ) (_) \(OO )_ ]],
[[,--./ ,--/ (,------.(`-')----. ,--.(_/,-.\ ,-(`-'),--./ ,-.)]],
[[| \ | | | .---'( OO).-. '\ \ / (_/ | ( OO)| `.' |]],
[[| . '| |)(| '--. ( _) | | | \ / / | | )| |'.'| |]],
[[| |\ | | .--' \| |)| |_ \ /_)(| |_/ | | | |]],
[[| | \ | | `---. ' '-' '\-'\ / | |'->| | | |]],
[[`--' `--' `------' `-----' `-' `--' `--' `--']],
},
opts = {
position = 'center',
hl = 'DashboardHeader',
},
}
local footers = {
[[☆*:.。. o(≧▽≦)o .。.:*☆]],
[[°˖✧ ◝(⁰▿⁰)◜✧˖°]],
[[✿ ♬ ゚+.(。◡‿◡)♪.+ ゚♬ ✿ ]],
[[— ฅ/ᐠ. ̫ .ᐟ\ฅ —]],
[[/ᐠ_ ꞈ _ᐟ\ɴʏᴀ~]],
[[૮₍˶ •. • ⑅₎ა]],
[[︶꒷꒦︶ ๋࣭ ⭑ ૮₍˶• . • ⑅₎ა]],
[[。*゚.*.。(っ ᐛ )っ 𝖍𝖎]],
[[ₓ 。 𐐪₍ᐢ. ̫ .⑅ᐢ₎𐑂↝]],
[[ଘ(੭ *ˊᵕˋ)੭ * ੈ♡‧₊˚]],
}
math.randomseed(os.time())
local footer = {
type = 'text',
val = footers[math.random(#footers)],
opts = {
position = 'center',
hl = 'DashboardFooter',
},
}
local button = function(sc, txt, keybind, keybind_opts)
local sc_ = sc:gsub('%s', ''):gsub('SPC', '<leader>')
local opts = {
position = 'center',
shortcut = sc,
cursor = 3,
width = 50,
align_shortcut = 'right',
hl = 'DashboardCenter',
hl_shortcut = 'DashboardShortcut',
}
if keybind then
keybind_opts = vim.F.if_nil(keybind_opts, { noremap = true, silent = true, nowait = true })
opts.keymap = { 'n', sc_, keybind, keybind_opts }
end
local function on_press()
local key = vim.api.nvim_replace_termcodes(sc_ .. '<Ignore>', true, false, true)
vim.api.nvim_feedkeys(key, 'normal', false)
end
return {
type = 'button',
val = txt,
on_press = on_press,
opts = opts,
}
end
local buttons = {
type = 'group',
val = {
button('SPC /', ' Live grep'),
button('SPC f m', ' Bookmarks'),
button('SPC f f', ' Find file'),
button('SPC f r', ' Recent files'),
button('SPC f p', ' Recent projects'),
button('SPC p l', ' Load last session'),
button('SPC SPC', ' Plugin manager'),
},
opts = { spacing = 1 },
}
local loaded = {
type = 'text',
val = '', -- this is overwritten in the autocmd below
opts = {
position = 'center',
hl = 'DashboardFooter',
},
}
-- Redraw the dashboard to get Lazy stats and overwrited 'loaded' value
vim.api.nvim_create_autocmd('User', {
pattern = 'LazyVimStarted',
callback = function()
local stats = require('lazy').stats()
loaded.val = '🎉 Neovim loaded '
.. stats.count
.. ' plugins in '
.. (math.floor(stats.startuptime * 100 + 0.5) / 100)
.. 'ms'
pcall(vim.cmd.AlphaRedraw)
end,
})
return {
layout = {
{ type = 'padding', val = 7 },
header,
{ type = 'padding', val = 2 },
buttons,
loaded,
{ type = 'padding', val = 1 },
footer,
{ type = 'padding', val = 7 },
},
opts = {
margin = 5,
noautocmd = true,
redraw_on_resize = true,
},
}

View File

@ -0,0 +1,135 @@
local colors = require('user.themes.' .. vim.g.colors_name .. '.colors')
local mappings = require('cokeline.mappings')
local components = {
separator = {
text = function(buffer)
return buffer.index ~= 1 and '' or ''
end,
fg = 'TabLineSel',
truncation = { priority = 2 },
},
space = { text = ' ', truncation = { priority = 2 } },
devicon = {
text = function(buffer)
return (mappings.is_picking_focus() or mappings.is_picking_close()) and (buffer.pick_letter .. ' ') or (buffer.devicon.icon .. ' ')
end,
fg = function(buffer)
if mappings.is_picking_close() then
return buffer.is_focused and colors.yellow or colors.red
end
if mappings.is_picking_focus() then
return buffer.is_focused and colors.yellow or colors.blue
end
return buffer.devicon.color
end,
style = function()
return (mappings.is_picking_focus() or mappings.is_picking_close()) and 'bold,italic' or nil
end,
truncation = { priority = 3 },
},
unique_prefix = {
text = function(buffer)
return buffer.unique_prefix
end,
fg = 'Comment',
style = 'italic',
truncation = { priority = 4, direction = 'left' },
},
filename = {
text = function(buffer)
return buffer.filename .. ' '
end,
style = function(buffer)
return buffer.is_focused and 'bold' or 'italic'
end,
truncation = { priority = 1, direction = 'left' },
},
file_readonly = {
text = function(buffer)
return (buffer.is_readonly or not vim.api.nvim_buf_get_option(buffer.number, 'modifiable')) and '' or ''
end,
fg = colors.red,
truncation = { priority = 3, direction = 'left' },
},
close_or_modified = {
text = function(buffer)
return buffer.is_modified and '' or ''
end,
fg = function(buffer)
return buffer.is_modified and colors.green or 'Comment'
end,
delete_buffer_on_left_click = true,
truncation = { priority = 3 },
},
}
local buffer_width = 28
local get_remaining_space = function(buffer)
local used_space = 0
for _, component in pairs(components) do
used_space = used_space + vim.fn.strwidth(
(type(component.text) == 'string' and component.text)
or (type(component.text) == 'function' and component.text(buffer))
)
end
return math.max(0, buffer_width - used_space)
end
local left_padding = {
text = function(buffer)
local remaining_space = get_remaining_space(buffer)
return string.rep(' ', remaining_space / 2 + remaining_space % 2)
end,
}
local right_padding = {
text = function(buffer)
local remaining_space = get_remaining_space(buffer)
return string.rep(' ', remaining_space / 2)
end,
}
return {
default_hl = {
fg = function(buffer)
return buffer.is_focused and 'Normal' or 'Comment'
end,
bg = 'NONE',
},
fill_hl = 'TabLineFill',
rendering = { max_buffer_width = buffer_width },
components = {
components.separator,
left_padding,
components.space,
components.devicon,
components.unique_prefix,
components.file_readonly,
components.filename,
right_padding,
components.close_or_modified,
},
tabs = {
placement = 'left',
components = {
{
text = function(tabpage)
return string.format(" %s ", tabpage.number)
end,
on_click = function(_, _, _, _, tabpage)
tabpage:focus()
end,
highlight = function(tabpage)
return tabpage.is_active and 'TabLineSel' or 'TabLine'
end,
truncation = { priority = 2 },
},
},
},
rhs = {
{
text = '' .. vim.fn.fnamemodify(vim.fn.getcwd(), ':t') .. ' ',
highlight = 'TabLineSel',
truncation = { priority = 2 },
},
},
}

View File

@ -0,0 +1,21 @@
local vars = require('user.config.vars')
return {
input = { enabled = false }, -- avoid loading nvim-cmp needlessly. Also, noice.nvim has nice input UI already
select = {
backend = { 'telescope', 'builtin', 'nui' },
nui = {
border = { style = vars.border },
win_options = { winblend = 0 },
},
builtin = {
border = vars.border,
win_options = { winblend = 0 },
mappings = {
['q'] = 'Close',
['<Esc>'] = 'Close',
['<CR>'] = 'Confirm',
},
},
},
}

View File

@ -0,0 +1,321 @@
local M = {}
local conditions = require('heirline.conditions')
local utils = require('heirline.utils')
local misc_utils = require('user.util.misc')
local lsp_utils = require('user.util.lsp')
local vars = require('user.config.vars')
M.align = { provider = '%=' }
M.dummy = { provider = '', hl = { fg = 'blue' } }
local vi_mode = {
n = { name = 'NORMAL', color = 'green' },
no = { name = 'OP', color = 'green' },
nov = { name = 'OP(v)', color = 'green' },
noV = { name = 'OP(V)', color = 'green' },
['no\22'] = { name = 'OP(^V)', color = 'green' },
niI = { name = 'NORMAL(I)', color = 'green' },
niR = { name = 'NORMAL(R)', color = 'green' },
niV = { name = 'NORMAL(V)', color = 'green' },
nt = { name = 'NORMAL(T)', color = 'green' },
ntT = { name = 'NORMAL(T)', color = 'green' },
v = { name = 'VISUAL', color = 'yellow' },
vs = { name = 'VISUAL(s)', color = 'yellow' },
V = { name = 'V-LINE', color = 'yellow' },
Vs = { name = 'V-LINE(s)', color = 'yellow' },
['\22'] = { name = 'V-BLOCK', color = 'yellow' },
['\22s'] = { name = 'V-BLOCK(s)', color = 'yellow' },
s = { name = 'SELECT', color = 'orange' },
S = { name = 'S-LINE', color = 'orange' },
['\19'] = { name = 'S-BLOCK', color = 'orange' },
i = { name = 'INSERT', color = 'blue' },
ic = { name = 'INSERT(c)', color = 'blue' },
ix = { name = 'INSERT(x)', color = 'blue' },
R = { name = 'REPLACE', color = 'red' },
Rc = { name = 'REPLACE(c)', color = 'red' },
Rx = { name = 'REPLACE(x)', color = 'red' },
Rv = { name = 'REPLACE(v)', color = 'red' },
Rvc = { name = 'REPLACE(vc)', color = 'red' },
Rvx = { name = 'REPLACE(vx)', color = 'red' },
c = { name = 'COMMAND', color = 'purple' },
cv = { name = 'EX', color = 'purple' },
r = { name = 'ENTER', color = 'cyan' },
rm = { name = 'MORE', color = 'cyan' },
['r?'] = { name = 'CONFIRM', color = 'cyan' },
['!'] = { name = 'SHELL', color = 'fg' },
t = { name = 'TERM', color = 'fg' },
}
local get_vi_mode = function(spec)
local vals = {}
for k, v in pairs(vi_mode) do
vals[k] = v[spec]
end
return vals
end
M.vi_mode = {
init = function(self)
self.mode = vim.fn.mode(1)
end,
static = {
mode_names = get_vi_mode('name'),
mode_colors = get_vi_mode('color'),
},
provider = function(self)
return '' .. self.mode_names[self.mode] .. ' '
end,
hl = function(self)
local mode = self.mode:sub(1, 1)
return { fg = self.mode_colors[mode], bold = true }
end,
update = {
'ModeChanged',
pattern = '*:*',
callback = vim.schedule_wrap(function()
vim.cmd('redrawstatus')
end),
},
}
M.file_size = {
condition = misc_utils.buffer_not_empty,
provider = function()
local suffix = { 'b', 'k', 'M', 'G', 'T', 'P', 'E' }
local fsize = vim.fn.getfsize(vim.api.nvim_buf_get_name(0))
fsize = fsize < 0 and 0 or fsize
if fsize == 0 then
return ''
end
if fsize < 1024 then
return fsize .. suffix[1] .. ' '
end
local i = math.floor((math.log(fsize) / math.log(1024)))
return string.format('%.2g%s ', fsize / math.pow(1024, i), suffix[i + 1])
end,
hl = { fg = 'blue', bold = true },
}
M.file_format = {
condition = misc_utils.buffer_not_empty,
provider = function()
local os = vim.bo.fileformat:upper()
local icon = ''
if os == 'UNIX' then
icon = ''
elseif os == 'MAC' then
icon = ''
else
icon = ''
end
return ' ' .. icon .. os
end,
hl = { fg = 'cyan' },
}
M.file_type = {
provider = function()
return ' ' .. string.upper(vim.bo.filetype)
end,
hl = { fg = 'blue', bold = true },
}
M.file_encoding = {
provider = function()
local enc = vim.bo.fenc ~= '' and vim.bo.fenc or vim.o.enc
return enc ~= 'utf-8' and (' ' .. enc:upper())
end,
hl = { fg = 'fg' },
}
local file_common = {
init = function(self)
self.filename = vim.api.nvim_buf_get_name(0)
end,
}
local file_icon = {
init = function(self)
local filename = self.filename
local extension = vim.fn.fnamemodify(filename, ':e')
self.icon, self.icon_color =
require('nvim-web-devicons').get_icon_color(filename, extension, { default = true })
end,
provider = function(self)
return self.icon and (self.icon .. ' ')
end,
hl = function(self)
return { fg = self.icon_color and self.icon_color or 'fg' }
end,
}
local file_name = {
provider = function(self)
if self.filename == '' then
return '[No Name]'
end
return vim.fn.fnamemodify(self.filename, ':p:t')
end,
hl = function()
if vim.bo.modified then
return { fg = 'cyan', bold = true }
end
return { fg = 'blue', bold = true }
end,
}
local file_flags = {
{
condition = function()
return vim.bo.modified
end,
provider = '',
hl = { fg = 'green' },
},
{
condition = function()
return not vim.bo.modifiable or vim.bo.readonly
end,
provider = '',
hl = { fg = 'red' },
},
}
M.file_info = utils.insert(file_common, file_icon, file_name, file_flags, { provider = '%<' })
M.ruler = {
provider = '%7(%l/%3L%):%2c %P',
hl = { fg = 'fg' },
}
M.lsp_servers = {
condition = conditions.lsp_attached,
update = { 'LspAttach', 'LspDetach' },
provider = function()
return '  [' .. table.concat(lsp_utils.lsp_active_clients(), ', ') .. ']'
end,
hl = { fg = 'purple' },
}
M.navic = {
condition = function()
return require('nvim-navic').is_available()
end,
provider = function()
return require('nvim-navic').get_location()
end,
update = 'CursorMoved',
}
M.diagnostics = {
condition = conditions.has_diagnostics,
update = { 'DiagnosticChanged', 'BufEnter' },
init = function(self)
self.errors = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.ERROR })
self.warnings = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.WARN })
self.hints = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.HINT })
self.infos = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity.INFO })
end,
{
provider = function(self)
return self.errors > 0 and (' ' .. vars.icons.notify.error .. ' ' .. self.errors)
end,
hl = { fg = utils.get_highlight('DiagnosticError').fg },
},
{
provider = function(self)
return self.warnings > 0 and (' ' .. vars.icons.notify.warn .. ' ' .. self.warnings)
end,
hl = { fg = utils.get_highlight('DiagnosticWarn').fg },
},
{
provider = function(self)
return self.hints > 0 and (' ' .. vars.icons.notify.hint .. ' ' .. self.hints)
end,
hl = { fg = utils.get_highlight('DiagnosticHint').fg },
},
{
provider = function(self)
return self.infos > 0 and (' ' .. vars.icons.notify.info .. ' ' .. self.infos)
end,
hl = { fg = utils.get_highlight('DiagnosticInfo').fg },
},
}
M.code_action = {
condition = conditions.lsp_attached,
update = { 'CursorMoved', 'LspAttach' },
provider = function()
if vim.b.has_code_action_text then
return ' ' .. vim.b.has_code_action_text
end
end,
hl = { fg = 'cyan', bold = true },
}
M.git = {
condition = conditions.is_git_repo,
init = function(self)
self.status_dict = vim.b.gitsigns_status_dict
self.has_changes = self.status_dict.added ~= 0 or self.status_dict.removed ~= 0 or self.status_dict.changed ~= 0
end,
hl = { fg = 'green', bold = true },
{
provider = function(self)
return '' .. self.status_dict.head
end,
},
{
condition = function(self)
return self.has_changes
end,
provider = '(',
},
{
provider = function(self)
local count = self.status_dict.added or 0
return count > 0 and ('+' .. count)
end,
hl = { fg = utils.get_highlight('DiffAdd').fg },
},
{
provider = function(self)
local count = self.status_dict.removed or 0
return count > 0 and ('-' .. count)
end,
hl = { fg = utils.get_highlight('DiffDelete').fg },
},
{
provider = function(self)
local count = self.status_dict.changed or 0
return count > 0 and ('~' .. count)
end,
hl = { fg = utils.get_highlight('DiffChange').fg },
},
{
condition = function(self)
return self.has_changes
end,
provider = ')',
},
}
M.debugger = {
condition = function()
local session = require('dap').session()
return session ~= nil
end,
provider = function()
return '' .. require('dap').status()
end,
hl = { fg = 'purple', bold = true },
}
M.macro = {
condition = function()
return vim.fn.reg_recording() ~= '' and vim.o.cmdheight == 0
end,
provider = function()
return ' @ Recording ' .. vim.fn.reg_recording()
end,
update = { 'RecordingEnter', 'RecordingLeave' },
hl = { fg = 'green', bold = true },
}
return M

View File

@ -0,0 +1,110 @@
local conditions = require('heirline.conditions')
local components = require('user.plugins.ui.heirline.components')
local excluded_buftype = { 'nofile', 'prompt', 'help', 'quickfix', 'terminal' }
local excluded_ft = {
'NvimTree',
'OverseerForm',
'TelescopePrompt',
'Trouble',
'aerial',
'aerial-nav',
'alpha',
'lazy',
'qf',
'toggleterm',
'undotree',
'dap-repl',
'dapui_console',
'dapui_watches',
'dapui_stacks',
'dapui_breakpoints',
'dapui_scopes',
}
require('heirline').setup {
statusline = {
hl = function()
if conditions.is_active() then
return 'StatusLine'
end
return 'StatusLineNC'
end,
fallthrough = false,
-- Statusline for special buffers
{
condition = function()
return conditions.buffer_matches {
buftype = excluded_buftype,
filetype = excluded_ft,
}
end,
{ components.file_info, flexible = 1 },
components.align,
{ components.file_type, flexible = 3 },
},
-- Inactive statusline
{
condition = function()
return not conditions.is_active()
end,
components.dummy,
components.file_size,
{ components.file_info, flexible = 1 },
components.align,
{ components.file_format, flexible = 2 },
{ components.file_encoding, flexible = 3 },
{ components.file_type, flexible = 3 },
},
-- Default statusline
{
components.dummy,
components.vi_mode,
components.file_size,
{ components.file_info, flexible = 1 },
{ components.debugger, flexible = 3 },
{ components.code_action, flexible = 2 },
{ components.macro, flexible = 2 },
components.align,
components.ruler,
{ components.file_format, flexible = 2 },
{ components.file_encoding, flexible = 3 },
{ components.file_type, flexible = 3 },
{ components.git, flexible = 1 },
},
},
winbar = {
hl = function()
if conditions.is_active() then
return 'WinBar'
end
return 'WinBarNC'
end,
fallthrough = false,
-- Inactive winbar
{
condition = function()
return not conditions.is_active()
end,
components.diagnostics,
components.align,
{ components.lsp_servers, flexible = 1 },
},
-- Regular winbar
{
{ components.navic, flexible = 2, { provider = '' } },
components.align,
components.diagnostics,
{ components.lsp_servers, flexible = 1 },
},
},
opts = {
disable_winbar_cb = function(args)
return conditions.buffer_matches({
buftype = excluded_buftype,
filetype = excluded_ft,
}, args.buf)
end,
colors = require('user.themes.' .. vim.g.colors_name .. '.colors'),
},
}

View File

@ -0,0 +1,194 @@
local tabline_provider = require('user.config.vars').tabline_provider
return {
{
'goolord/alpha-nvim',
event = 'VimEnter',
opts = function()
return require('user.plugins.ui.alpha')
end,
config = function(_, opts)
require('alpha').setup(opts)
-- Disable tabline in Alpha buffer
local showtabline_val = vim.o.showtabline
if showtabline_val ~= 0 then
vim.api.nvim_create_autocmd('User', {
pattern = 'AlphaReady',
callback = function()
vim.opt.showtabline = 0
vim.api.nvim_create_autocmd('BufUnload', {
buffer = 0,
once = true,
callback = function()
vim.opt.showtabline = showtabline_val
end,
})
end,
})
end
end,
},
{
'tiagovla/scope.nvim',
event = 'VeryLazy',
keys = {
{
'<leader>fB',
function()
require('telescope').load_extension('scope')
vim.cmd.Telescope { args = { 'scope', 'buffers' }}
end,
desc = 'Scoped buffers',
},
},
config = true,
},
{
'nanozuki/tabby.nvim',
enabled = vim.o.showtabline ~= 0 and tabline_provider == 'tabby',
event = 'VeryLazy',
config = function()
require('user.plugins.ui.tabby')
end,
},
{
'willothy/nvim-cokeline',
enabled = vim.o.showtabline ~= 0 and tabline_provider == 'cokeline',
event = 'VeryLazy',
keys = {
{ '[b', '<Plug>(cokeline-focus-prev)', desc = 'Previous buffer' },
{ ']b', '<Plug>(cokeline-focus-next)', desc = 'Next buffer' },
{ '<localleader>b', function() require('cokeline.mappings').pick('focus') end, desc = 'Pick buffer' },
{ '<localleader>q', function() require('cokeline.mappings').pick('close') end, desc = 'Close picked buffer' },
},
opts = function()
return require('user.plugins.ui.cokeline')
end,
},
{
'rebelot/heirline.nvim',
event = 'UIEnter',
config = function()
require('user.plugins.ui.heirline')
end,
},
{
'nvim-tree/nvim-tree.lua',
cmd = { 'NvimTreeToggle', 'NvimTreeFindFileToggle', 'NvimTreeFocus' },
keys = {
{ '<leader>n', function() require('nvim-tree.api').tree.toggle(false, true) end, desc = 'NvimTree' },
{ '<leader>N', function() require('nvim-tree.api').tree.focus() end, desc = 'NvimTree (focus)' },
},
opts = require('user.plugins.ui.tree'),
},
{
'petertriho/nvim-scrollbar',
event = 'BufReadPost',
opts = {
set_highlights = false,
show_in_active_only = true,
handle = { blend = 0 },
handlers = { cursor = false },
excluded_filetypes = {
'alpha',
'lazy',
'notify',
'aerial',
'Trouble',
'NvimTree',
'qf',
'prompt',
'noice',
'OverseerForm',
'TelescopePrompt',
},
},
},
{
'folke/which-key.nvim',
event = 'VeryLazy',
config = function()
require('user.plugins.ui.which-key')
end,
},
{
'stevearc/dressing.nvim',
event = 'VeryLazy',
init = function()
---@diagnostic disable-next-line: duplicate-set-field
vim.ui.select = function(...)
require('lazy').load({ plugins = { 'dressing.nvim' } })
return vim.ui.select(...)
end
end,
opts = require('user.plugins.ui.dressing'),
},
{
'folke/noice.nvim',
event = 'VeryLazy',
dependencies = {
{
'rcarriga/nvim-notify',
keys = {
{
'<leader>uN', function()
require('notify').dismiss { silent = true, pending = true }
end,
desc = 'Delete all notifications',
},
{
'<leader>un', function()
require('telescope').load_extension('notify')
vim.cmd.Telescope { args = { 'notify' } }
end,
desc = 'Show all notifications',
},
},
opts = require('user.plugins.ui.notify')
},
},
keys = {
{ '<S-Enter>', function() require('noice').redirect(vim.fn.getcmdline()) end, mode = 'c', desc = 'Redirect Cmdline' },
{ '<leader>ul', function() require('noice').cmd('last') end, desc = 'Noice Last Message' },
{ '<leader>uh', function() require('noice').cmd('history') end, desc = 'Noice History' },
{ '<leader>ua', function() require('noice').cmd('all') end, desc = 'Noice All' },
{ '<C-f>', function() if not require('noice.lsp').scroll(4) then return '<C-f>' end end, silent = true, expr = true, desc = 'Scroll forward', mode = {'i', 'n', 's'} },
{ '<C-b>', function() if not require('noice.lsp').scroll(-4) then return '<C-b>' end end, silent = true, expr = true, desc = 'Scroll backward', mode = {'i', 'n', 's'}},
},
opts = require('user.plugins.ui.noice'),
},
{
'folke/trouble.nvim',
cmd = { 'Trouble', 'TroubleToggle' },
keys = {
{
'[q',
function()
if require('trouble').is_open() then
require('trouble').previous { skip_groups = true, jump = true }
else
vim.cmd.cprev()
end
end,
desc = 'Previous trouble/quickfix item',
},
{
']q',
function()
if require('trouble').is_open() then
require('trouble').next { skip_groups = true, jump = true }
else
vim.cmd.cnext()
end
end,
desc = 'Next trouble/quickfix item',
},
{ 'gL', '<cmd>TroubleToggle loclist<CR>', desc = 'Location list (Trouble)' },
{ 'gQ', '<cmd>TroubleToggle quickfix<CR>', desc = 'Quickfix (Trouble)' },
},
opts = function()
return require('user.plugins.ui.trouble')
end,
},
}

View File

@ -0,0 +1,59 @@
local vars = require('user.config.vars')
return {
lsp = {
-- `lsp_progress` builtin without progress bar
progress = {
enabled = false,
format = {
'{data.progress.percentage}% ',
{ '{spinner} ', hl_group = 'NoiceLspProgressSpinner' },
{ '{data.progress.title} ', hl_group = 'NoiceLspProgressTitle' },
{ '{data.progress.client} ', hl_group = 'NoiceLspProgressClient' },
},
},
override = {
['cmp.entry.get_documentation'] = true,
['vim.lsp.util.convert_input_to_markdown_lines'] = true,
-- ['vim.lsp.util.stylize_markdown'] = true,
},
},
presets = { command_palette = true, long_message_to_split = true },
views = {
mini = { win_options = { winblend = 0 } },
cmdline_popup = { border = { style = vars.border } },
confirm = { border = { style = vars.border } },
popup = { border = { style = vars.border } },
popupmenu = { border = { style = vars.border } },
hover = {
relative = 'cursor',
border = { style = vars.border },
position = { row = 2, col = 2 },
},
},
cmdline = {
format = {
-- `inc_rename` preset, but with different title
rename = {
pattern = '^:%s*IncRename%s+',
title = ' Rename ',
icon = '',
conceal = true,
opts = {
relative = 'cursor',
size = { min_width = 20 },
position = { row = -3, col = 0 },
},
},
},
},
routes = {
{
filter = {
event = 'msg_show',
find = '%d+L, %d+B',
},
view = 'mini',
},
},
}

View File

@ -0,0 +1,24 @@
local vars = require('user.config.vars')
return {
level = vars.loglevel,
stages = 'slide',
on_open = function(win)
vim.api.nvim_win_set_config(win, {
border = vars.border,
focusable = false,
})
end,
render = 'default',
timeout = 2000,
background_colour = 'NormalFloat',
minimum_width = 40,
icons = {
ERROR = vars.icons.notify.error .. ' ',
WARN = vars.icons.notify.warn .. ' ',
INFO = vars.icons.notify.info .. ' ',
DEBUG = vars.icons.notify.debug .. ' ',
TRACE = vars.icons.notify.trace .. ' ',
},
top_down = true,
}

View File

@ -0,0 +1,51 @@
local theme = {
fill = 'TabLineFill',
head = 'TabLineSel',
current_tab = 'TabLineSel',
tab = 'TabLineFill',
}
require('tabby.tabline').set(function(line)
return {
{
{ '' .. vim.fn.fnamemodify(vim.fn.getcwd(), ':t') .. ' ', hl = theme.head },
line.sep('', theme.head, theme.fill),
},
line.tabs().foreach(function(tab)
local hl = tab.is_current() and theme.current_tab or theme.tab
return {
line.sep('', hl, theme.fill),
tab.is_current() and '󱓻' or '󱓼',
tab.number(),
line.sep('', hl, theme.fill),
hl = hl,
margin = ' ',
}
end),
line.spacer(),
line.wins_in_tab(line.api.get_current_tab()).foreach(function(win)
local name = win.buf_name()
local icon, color = require('nvim-web-devicons').get_icon_color(name, vim.fn.fnamemodify(name, ':e'), { default = true })
local hl = win.is_current() and theme.current_tab or theme.tab
return {
line.sep('', hl, theme.fill),
{
icon,
hl = {
fg = color,
bg = require('tabby.module.highlight').extract(hl).bg,
},
},
win.buf_name(),
win.buf().is_changed() and '' or '',
line.sep('', hl, theme.fill),
hl = hl,
margin = ' ',
}
end),
hl = theme.fill,
}
end, {
buf_name = { mode = 'shorten' },
})

View File

@ -0,0 +1,102 @@
local vars = require('user.config.vars')
return {
disable_netrw = true,
hijack_cursor = true,
respect_buf_cwd = true,
sync_root_with_cwd = true,
hijack_directories = { enable = false },
diagnostics = {
enable = true,
icons = {
hint = vars.icons.notify.hint,
info = vars.icons.notify.info,
warning = vars.icons.notify.warn,
error = vars.icons.notify.error,
},
},
update_focused_file = { enable = true, update_root = true },
system_open = {
cmd = vim.loop.os_uname().sysname == 'Darwin' and 'open' or 'xdg-open',
},
filters = {
custom = {
'^\\.bzr$',
'^\\.git$',
'^\\.hg$',
'^\\.pijul$',
'^\\.svn$',
'^_dars$',
'^node_modules$',
'^bazel-out$',
'^bazel-bin$',
'^bazel-testlogs$',
'^plz-out$',
'^\\.plz-cache$',
'^\\.plz-http-cache$',
},
},
git = { ignore = false, timeout = 500 },
view = { width = 35, side = 'left' },
renderer = {
highlight_git = true,
indent_markers = { enable = true },
icons = {
symlink_arrow = '',
glyphs = {
default = '',
symlink = '',
bookmark = '',
modified = '',
folder = {
arrow_closed = '',
arrow_open = '',
default = '󰉋',
open = '󰝰',
empty = '',
empty_open = '',
symlink = '',
symlink_open = '',
},
git = {
unstaged = '',
staged = '',
unmerged = '',
renamed = '',
untracked = '',
deleted = '',
ignored = '',
},
},
},
special_files = { 'Cargo.toml', 'Makefile', 'README.md', 'package.json' },
},
actions = {
file_popup = {
open_win_config = {
border = vars.border,
},
},
open_file = {
resize_window = false,
window_picker = {
exclude = {
filetype = {
'alpha',
'lazy',
'aerial',
'OverseerForm',
'TelescopePrompt',
'notify',
'undotree',
'Trouble',
'NvimTree',
'diff',
'qf',
},
buftype = { 'terminal', 'nofile', 'help' },
},
},
},
},
}

View File

@ -0,0 +1,20 @@
local icons = require('user.config.vars').icons
return {
fold_open = '',
fold_closed = '',
action_keys = {
open_split = { '<c-h>' },
open_vsplit = { '<c-v>' },
open_tab = { '<c-t>' },
},
auto_open = false,
auto_close = true,
signs = {
error = icons.notify.error,
warning = icons.notify.warn,
information = icons.notify.info,
hint = icons.notify.hint,
other = icons.notify.trace,
},
}

View File

@ -0,0 +1,57 @@
local wk = require('which-key')
wk.setup {
plugins = {
spelling = { enabled = true, suggestions = 30 },
presets = {
operators = false,
motions = false,
text_objects = false,
windows = true,
nav = true,
z = true,
g = true,
},
},
key_labels = {
['<space>'] = 'SPC',
['<cr>'] = 'RET',
['<tab>'] = 'TAB',
},
icons = {
breadcrumb = '»',
separator = '󰜴',
group = '+',
},
window = {
border = require('user.config.vars').border,
position = 'bottom',
winblend = 0,
},
layout = { spacing = 10, align = 'center' },
ignore_missing = false, -- https://github.com/folke/which-key.nvim/issues/355
}
-- Register key group names after <leader>
wk.register({
d = { name = 'Debug' },
e = { name = 'Editor' },
f = {
name = 'Finder',
s = { name = 'Symbols' },
},
g = { name = 'Git' },
l = { name = 'LSP' },
s = { name = 'Search/Replace' },
t = { name = 'Tasks' },
p = { name = 'Session' },
q = { name = 'Quit' },
u = { name = 'UI' },
['<Tab>'] = { name = 'Tab' },
}, { prefix = '<leader>' })
wk.register({
d = { name = 'Debug' },
e = { name = 'Editor' },
g = { name = 'Git' },
s = { name = 'Search/Replace' },
}, { prefix = '<leader>', mode = 'x' })

View File

@ -0,0 +1,24 @@
local colors = require('user.themes.' .. vim.g.colors_name .. '.colors')
--- Get Carbon theme name from the current Neovim theme
---@param name string
local function get_theme(name)
if name == 'nord' then
return 'Nord'
elseif name == 'onedark' then
return 'One Dark'
end
return 'VSCode'
end
return {
options = {
theme = get_theme(vim.g.colors_name),
bg = colors.blue,
window_theme = 'none',
font_family = 'Cascadia Code',
watermark = false,
drop_shadow = true,
line_numbers = false,
},
}

View File

@ -0,0 +1,38 @@
local ccc = require('ccc')
ccc.setup {
default_color = '#000000',
bar_char = '',
point_char = '',
bar_len = 30,
win_opts = {
relative = 'cursor',
row = 1,
col = 1,
style = 'minimal',
border = require('user.config.vars').border,
},
inputs = {
ccc.input.rgb,
ccc.input.hsl,
ccc.input.cmyk,
},
outputs = {
ccc.output.hex,
ccc.output.hex_short,
ccc.output.css_rgb,
ccc.output.css_hsl,
},
pickers = {
ccc.picker.hex,
ccc.picker.css_rgb,
ccc.picker.css_hsl,
},
convert = {
{ ccc.picker.hex, ccc.output.css_rgb },
{ ccc.picker.css_rgb, ccc.output.css_hsl },
{ ccc.picker.css_hsl, ccc.output.hex },
},
save_on_quit = false,
highlight_mode = 'bg',
}

View File

@ -0,0 +1,37 @@
local gc = require('git-conflict')
gc.setup {
disable_diagnostics = true,
default_mappings = false,
default_commands = false,
}
vim.api.nvim_create_autocmd('User', {
pattern = 'GitConflictDetected',
once = true,
callback = function()
local bufnr = vim.api.nvim_get_current_buf()
local actions = {
['Base change'] = 'base',
['Both changes'] = 'both',
['Current change'] = 'ours',
['Incoming change'] = 'theirs',
['None of the changes'] = 'none',
}
vim.api.nvim_buf_create_user_command(bufnr, 'GitConflict', function()
vim.ui.select(vim.tbl_keys(actions), { prompt = 'Select a conflict action' }, function(choice)
if choice then gc.choose(actions[choice]) end
end)
end, { nargs = 0 })
vim.keymap.set('n', '<localleader>c', '<cmd>GitConflict<CR>', {
buffer = true,
noremap = true,
silent = true,
desc = 'Resolve git conflict',
})
end,
desc = 'Custom user command for git-conflict',
group = vim.api.nvim_create_augroup('UserGitConflict', { clear = true }),
})

View File

@ -0,0 +1,53 @@
return {
signs = {
add = { text = '+' },
change = { text = '~' },
delete = { text = '_' },
topdelete = { text = '' },
changedelete = { text = '-' },
untracked = { text = '+' },
},
current_line_blame_opts = { virt_text_pos = 'right_align' },
preview_config = { border = require('user.config.vars').border },
on_attach = function(bufnr)
local gs = package.loaded.gitsigns
local function map(mode, l, r, opts)
opts = vim.tbl_extend('force', { noremap = true, silent = true }, opts)
opts.buffer = bufnr
vim.keymap.set(mode, l, r, opts)
end
-- stylua: ignore start
map('n', ']g', function()
if vim.wo.diff then
return ']g'
end
vim.schedule(function()
gs.next_hunk()
end)
return '<Ignore>'
end, { expr = true, desc = 'Next hunk' })
map('n', '[g', function()
if vim.wo.diff then
return '[g'
end
vim.schedule(function()
gs.prev_hunk()
end)
return '<Ignore>'
end, { expr = true, desc = 'Previous hunk' })
map({ 'n', 'x' }, '<leader>gs', gs.stage_hunk, { desc = 'Stage hunk' })
map({ 'n', 'x' }, '<leader>gr', gs.reset_hunk, { desc = 'Reset hunk' })
map('n', '<leader>gp', gs.preview_hunk, { desc = 'Preview hunk' })
map('n', '<leader>gu', gs.undo_stage_hunk, { desc = 'Undo staged hunk' })
map('n', '<leader>gU', gs.reset_buffer_index, { desc = 'Reset buffer index' })
map('n', '<leader>gS', gs.stage_buffer, { desc = 'Stage all hunks in buffer' })
map('n', '<leader>gR', gs.reset_buffer, { desc = 'Reset all hunks in buffer' })
map('n', '<leader>gb', function() gs.blame_line { full = true } end, { desc = 'Blame current line' })
map('n', '<leader>gd', gs.diffthis, { desc = 'Show diff against current index' })
map('n', '<leader>gD', function() gs.diffthis('~') end, { desc = 'Show diff against last commit' })
map('n', '<leader>gz', gs.toggle_deleted, { desc = 'Toggle showing deleted hunk' })
map({ 'o', 'x' }, 'ih', ':<C-u>Gitsigns select_hunk<CR>', { desc = 'Select git hunk' })
map('n', 'gh', function() gs.setqflist('attached') end, { desc = 'Show git hunks in attached buffers' })
end,
}

View File

@ -0,0 +1,342 @@
local vars = require('user.config.vars')
return {
{
'echasnovski/mini.bufremove',
opts = { silent = true },
config = function(_, opts)
require('mini.bufremove').setup(opts)
end,
},
{
'akinsho/toggleterm.nvim',
cmd = 'ToggleTerm',
keys = {
{ [[<C-\>]], '<cmd>ToggleTerm<CR>', desc = 'Terminal' },
{ [[<C-S-\>]], '<cmd>ToggleTerm direction=float<CR>', desc = 'Float terminal' },
},
opts = {
shade_terminals = false,
float_opts = {
border = vars.border,
winblend = 0,
},
winbar = { enabled = true },
},
},
{
'nvim-telescope/telescope.nvim',
cmd = 'Telescope',
keys = {
-- File pickers
{ '<leader>/', '<cmd>Telescope live_grep<CR>', desc = 'Live grep' },
{ '<leader>fe', '<cmd>Telescope file_browser<CR>', desc = 'File browser' },
{ '<leader>ff', '<cmd>Telescope find_files<CR>', desc = 'Files' },
-- Vim pickers
{ '<leader>:', '<cmd>Telescope command_history<CR>', desc = 'Command history' },
{ '<leader>fa', '<cmd>Telescope autocommands<CR>', desc = 'Auto commands' },
{ '<leader>fb', '<cmd>Telescope buffers sort_mru=true sort_lastused=true<CR>', desc = 'Buffers' },
{ '<leader>fh', '<cmd>Telescope help_tags<CR>', desc = 'Help pages' },
{ '<leader>fk', '<cmd>Telescope keymaps<CR>', desc = 'Keymaps (normal mode)' },
{ '<leader>fm', '<cmd>Telescope marks<CR>', desc = 'Marks' },
{ '<leader>fo', '<cmd>Telescope vim_options<CR>', desc = 'Vim options' },
{ '<leader>fr', '<cmd>Telescope oldfiles<CR>', desc = 'Recent files' },
{ '<leader>fz', '<cmd>Telescope current_buffer_fuzzy_find<CR>', desc = 'Current buffer' },
-- Symbols
{
'<leader>fsg',
function()
require('telescope.builtin').symbols { sources = { 'gitmoji' }, prompt_title = 'Gitmoji' }
end,
desc = 'Gitmoji',
},
{
'<leader>fsj',
function()
require('telescope.builtin').symbols { sources = { 'emoji' }, prompt_title = 'Emoji' }
end,
desc = 'Emoji',
},
{
'<leader>fsk',
function()
require('telescope.builtin').symbols { sources = { 'kaomoji' }, prompt_title = 'Kaomoji' }
end,
desc = 'Kaomoji',
},
{
'<leader>fsn',
function()
require('telescope.builtin').symbols { sources = { 'nerd' }, prompt_title = 'Nerd-fonts' }
end,
desc = 'Nerd-fonts',
},
-- Git pickers
{ '<leader>ga', '<cmd>Telescope git_stash<CR>', desc = 'Stash items' },
{ '<leader>gm', '<cmd>Telescope git_branches<CR>', desc = 'Branches' },
{ '<leader>gc', '<cmd>Telescope git_bcommits<CR>', desc = 'Buffer commits' },
{ '<leader>gC', '<cmd>Telescope git_commits<CR>', desc = 'Commits' },
},
dependencies = {
'nvim-telescope/telescope-file-browser.nvim',
{ 'nvim-telescope/telescope-fzf-native.nvim', build = 'make' },
{
'nvim-telescope/telescope-symbols.nvim',
-- there is only the data/ directory to care about
init = function()
require('lazy.core.loader').disable_rtp_plugin('telescope-symbols.nvim')
end,
},
},
opts = function()
return require('user.plugins.util.telescope')
end,
config = function(_, opts)
local telescope = require('telescope')
telescope.setup(opts)
-- NOTE: explicitly set after the setup so the options are applied correctly
telescope.load_extension('file_browser')
telescope.load_extension('fzf')
end,
},
{
'LukasPietzschmann/telescope-tabs',
keys = {
{ '<leader>f<Tab>', function() require('telescope-tabs').list_tabs() end, desc = 'Tabs' },
},
opts = {
entry_formatter = function(tab_id, _, file_names, _, is_current)
local current_icon = is_current and '' or ' '
if require('user.util.misc').has('tabby.nvim') then
local tab_name = require('tabby.feature.tab_name').get(tab_id)
return string.format('%d: %s%s', tab_id, current_icon, tab_name)
end
return string.format('%d: %s%s', tab_id, current_icon, table.concat(file_names, ', '))
end,
entry_ordinal = function(tab_id, _, file_names)
if require('user.util.misc').has('tabby.nvim') then
return require('tabby.feature.tab_name').get(tab_id)
end
return table.concat(file_names, ' ')
end,
},
},
{
'ahmedkhalf/project.nvim',
event = { 'BufReadPost', 'BufNewFile' },
keys = {
{
'<leader>fp', function()
local telescope = require('telescope')
telescope.load_extension('projects')
telescope.extensions.projects.projects()
end,
desc = 'Recent projects',
},
},
config = function()
require('user.plugins.util.project')
end,
},
{
'stevearc/overseer.nvim',
cmd = {
'OverseerToggle',
'OverseerBuild',
'OverseerInfo',
'OverseerRunCmd',
'OverseerRun',
},
keys = {
{ '<leader>tb', '<cmd>OverseerBuild<CR>', desc = 'Build task' },
{ '<leader>ti', '<cmd>OverseerInfo<CR>', desc = 'Info' },
{ '<leader>tl', '<cmd>OverseerToggle<CR>', desc = 'Task list' },
{ '<leader>tr', '<cmd>OverseerRun<CR>', desc = 'Run task' },
},
opts = function()
return require('user.plugins.util.overseer')
end,
},
{
'stevearc/stickybuf.nvim',
event = 'BufReadPost',
cmd = { 'PinBuffer', 'PinBuftype', 'Unpin', 'PinFileType' },
opts = { get_auto_pin = require('user.plugins.util.stickybuf') },
},
{
'NeogitOrg/neogit',
cmd = 'Neogit',
keys = {
{'<leader>go', '<cmd>Neogit<CR>', desc = 'Neogit' },
},
dependencies = {
{
'sindrets/diffview.nvim',
cmd = { 'DiffviewOpen', 'DiffviewFileHistory' },
},
},
opts = {
signs = {
section = { '󰄾', '󰄼' },
item = { '', '' },
},
disable_context_highlighting = true,
integrations = { diffview = true, telescope = true },
telescope_sorter = function()
return require("telescope").extensions.fzf.native_fzf_sorter()
end,
},
},
{
'lewis6991/gitsigns.nvim',
event = { 'BufNewFile', 'BufReadPost' },
dependencies = 'plenary.nvim',
opts = require('user.plugins.util.gitsigns'),
},
{
'akinsho/git-conflict.nvim',
event = { 'BufReadPost', 'BufNewFile' },
keys = {
{ '[x', function() require('git-conflict').find_prev('ours') end, desc = 'Previous git conflict' },
{ ']x', function() require('git-conflict').find_next('ours') end, desc = 'Previous git conflict' },
},
config = function()
require('user.plugins.util.git-conflict')
end,
},
{
'cshuaimin/ssr.nvim',
keys = {
{ '<leader>ss', function() require('ssr').open() end, mode = { 'x', 'n' }, desc = 'Structural search/replace' },
},
opts = { border = vars.border },
},
{
'nvim-pack/nvim-spectre',
keys = {
{ '<leader>so', function() require('spectre').open() end, desc = 'Search/Replace (Spectre)' },
{ '<leader>so', function() require('spectre').open_visual() end, desc = 'Search/Replace selection (Spectre)', mode = 'x' },
{ '<leader>sp', function() require('spectre').open_file_search() end, desc = 'Search/Replace in current file' },
},
opts = { find_engine = { rg = { args = vars.rg_args } } },
},
{
'uga-rosa/ccc.nvim',
cmd = { 'CccPick', 'CccConvert', 'CccHighlighterToggle' },
keys = {
{ '<leader>ec', '<cmd>CccPick<CR>', desc = 'Pick color' },
{ '<leader>eC', '<cmd>CccPick<CR>', desc = 'Convert color under cursor' },
{ '<leader>uc', '<cmd>CccHighlighterToggle<CR>', desc = 'Highlight color text' },
},
config = function()
require('user.plugins.util.ccc')
end,
},
{
'folke/persistence.nvim',
event = 'BufReadPre',
keys = {
{ '<leader>ps', function() require('persistence').save() end, desc = 'Save session for current directory' },
{ '<leader>pd', function() require('persistence').stop() end, desc = 'Don\'t save current session' },
{ '<leader>pr', function() require('persistence').load() end, desc = 'Restore session' },
{ '<leader>pl', function() require('persistence').load { last = true } end, desc = 'Restore last session' },
},
opts = { options = vim.opt.sessionoptions:get() },
},
{
'michaelb/sniprun',
build = 'cargo build --release',
cmd = { 'SnipRun', 'SnipInfo' },
keys = {
{ '<leader>ex', '<cmd>SnipRun<CR>', desc = 'Execute current line' },
{ '<leader>ex', '<cmd>SnipRun<CR>', desc = 'Execute selection', mode = 'x' },
},
opts = {
display = { 'NvimNotify' },
display_options = { notification_timeout = 2000 },
show_no_output = {
'Classic',
'NvimNotify',
'TempFloatingWindow',
},
},
},
{
'rest-nvim/rest.nvim',
keys = {
{ 'gu', function() require('rest-nvim').run() end, desc = 'cURL request under cursor' },
},
opts = { result_split_in_place = true },
},
{
'mbbill/undotree',
cmd = 'UndotreeToggle',
keys = {
{ '<localleader>u', '<cmd>UndotreeToggle<CR>', desc = 'Undotree' },
},
init = function()
vim.g.undotree_WindowLayout = 2
vim.g.undotree_SplitWidth = 30
vim.g.undotree_DiffpaneHeight = 10
vim.g.undotree_SetFocusWhenToggle = 1
vim.g.undotree_RelativeTimestamp = 1
end,
},
{
'potamides/pantran.nvim',
cmd = 'Pantran',
keys = {
{ '<leader>er', function() return require('pantran').motion_translate() end, expr = true, desc = 'Translate (motion)' },
{ '<leader>eR', function() return require('pantran').motion_translate() .. '_' end, expr = true, desc = 'Translate (cursor)' },
{ '<leader>er', function() return require('pantran').motion_translate() end, expr = true, mode = 'x', desc = 'Translate' },
},
opts = function()
return require('user.plugins.util.pantran')
end,
},
{
'iamcco/markdown-preview.nvim',
build = 'cd app && pnpm install --prod',
cmd = { 'MarkdownPreviewToggle', 'MarkdownPreview' },
keys = {
{
'<localleader>p',
ft = { 'markdown', 'rmd' },
'<cmd>MarkdownPreviewToggle<CR>',
desc = 'Preview Markdown file',
},
},
opts = {
mkdp_browser = vim.loop.os_uname().sysname == 'Darwin' and 'open' or 'xdg-open',
mkdp_refresh_slow = 1,
mkdp_filetypes = { 'markdown', 'rmd' },
mkdp_echo_preview_url = 0,
mkdp_preview_options = { disable_filename = 1 },
},
config = function(_, opts)
for key, val in pairs(opts) do
vim.g[key] = val
end
vim.cmd('do FileType')
end,
},
{
'ellisonleao/carbon-now.nvim',
cmd = 'CarbonNow',
keys = {
{ mode = { 'n', 'x' }, '<leader>ui', '<cmd>CarbonNow<CR>', desc = 'Carbon' },
},
opts = function()
return require('user.plugins.util.carbon-now')
end,
},
{
'dstein64/vim-startuptime',
cmd = 'StartupTime',
init = function()
vim.g.startuptime_tries = 10
end,
},
}

View File

@ -0,0 +1,24 @@
local win_opts = {
border = require('user.config.vars').border,
win_opts = { winblend = 0 },
}
return {
strategy = require('user.util.misc').has('toggleterm.nvim') and {
'toggleterm',
hidden = false,
open_on_start = false,
use_shell = false,
} or 'terminal',
auto_detect_success_color = false,
task_list = {
default_detail = 2,
max_width = { 120, 0.3 },
min_width = { 40, 0.2 },
direction = 'right',
},
form = win_opts,
confirm = win_opts,
task_win = win_opts,
dap = false, -- enable the integration manually
}

View File

@ -0,0 +1,30 @@
local border = require('user.config.vars').border
local title_border
if border == 'single' or border == 'rounded' then
title_border = { '', '' }
else
title_border = { '', '' }
end
return {
default_engine = 'google',
command = { default_mode = 'interactive' },
ui = {
width_percentage = 0.8,
height_percentage = 0.6,
},
help = { separator = '' },
select = {
prompt_prefix = '',
selection_caret = '',
},
window = {
title_border = title_border,
window_config = { border = border },
options = {
winhighlight = 'Normal:NormalFloat,SignColumn:NormalFloat,FloatBorder:FloatBorder',
},
},
controls = { updatetime = vim.opt.updatetime:get() },
}

View File

@ -0,0 +1,16 @@
require('project_nvim').setup {
patterns = {
'.bzr',
'.git',
'.hg',
'.pijul',
'.svn',
'.fslckout',
'_darcs',
'>Code',
'Makefile',
'package.json',
'go.mod',
},
show_hidden = true,
}

View File

@ -0,0 +1,34 @@
local filetypes = {
'aerial',
'NvimTree',
'neotest-summary',
'startuptime',
'toggleterm',
'notify',
'OverseerList',
'gitcommit',
'noice',
'undotree',
}
local buftypes = { 'terminal', 'help', 'quickfix' }
-- Essentially a modified version of require('stickybuf').should_auto_pin()
return function(bufnr)
local buftype = vim.bo[bufnr].buftype
local filetype = vim.bo[bufnr].filetype
local bufname = vim.api.nvim_buf_get_name(bufnr)
if vim.tbl_contains(filetypes, filetype) then
return 'filetype'
elseif vim.tbl_contains(buftypes, buftype) then
return 'buftype'
elseif buftype == 'prompt' or vim.startswith(bufname, 'DAP ') then
return 'bufnr'
elseif bufname:match('Neogit.*Popup') then
return 'bufnr'
elseif filetype == 'NeogitStatus' or filetype == 'NeogitLog' or filetype == 'NeogitGitCommandHistory' then
if vim.fn.winnr('$') > 1 then
return 'filetype'
end
end
end

View File

@ -0,0 +1,137 @@
local border_style = require('user.config.vars').border
local layout = require('user.config.vars').telescope_layout
local borderchars = {
horizontal = {
single = { '', '', '', '', '', '', '', '' },
rounded = { '', '', '', '', '', '', '', '' },
double = { '', '', '', '', '', '', '', '' },
},
bottom_pane = {
single = {
prompt = { '', '', ' ', '', '', '', ' ', ' ' },
results = { '', ' ', '', '', '', '', '', '' },
preview = { '', '', '', '', '', '', '', '' },
},
rounded = {
prompt = { '', '', ' ', '', '', '', ' ', ' ' },
results = { '', ' ', '', '', '', '', '', '' },
preview = { '', '', '', '', '', '', '', '' },
},
double = {
prompt = { '', '', ' ', '', '', '', ' ', ' ' },
results = { '', ' ', '', '', '', '', '', '' },
preview = { '', '', '', '', '', '', '', '' },
},
},
cursor = {
single = {
prompt = { '', '', ' ', '', '', '', ' ', ' ' },
results = { '', '', '', '', '', '', '', '' },
preview = { '', '', '', '', '', '', '', '' },
},
rounded = {
prompt = { '', '', ' ', '', '', '', '', '' },
results = { '', '', '', '', '', '', '', '' },
preview = { '', '', '', '', '', '', '', '' },
},
double = {
prompt = { '', '', ' ', '', '', '', '', '' },
results = { '', '', '', '', '', '', '', '' },
preview = { '', '', '', '', '', '', '', '' },
},
},
}
local ignore_patterns = {
'^%.bzr/',
'^%.git/',
'^%.hg/',
'^%.pijul/',
'^%.svn/',
'^_darcs/',
'^node_modules/',
'^bazel%-out/',
'^bazel%-bin/',
'^bazel%-testlogs/',
'^plz%-out/',
'^%.plz%-cache/',
'^%.plz%-http%-cache/',
}
return {
defaults = {
prompt_prefix = '',
selection_caret = '',
sorting_strategy = 'ascending',
mappings = {
i = {
['<C-t>'] = require('trouble.providers.telescope').open_with_trouble,
['<A-t>'] = require('trouble.providers.telescope').open_selected_with_trouble,
['<A-j>'] = 'cycle_history_prev',
['<A-k>'] = 'cycle_history_next',
},
n = {
['q'] = 'close',
},
},
dynamic_preview_title = true,
layout_strategy = layout,
layout_config = {
bottom_pane = {
height = 0.4,
preview_width = 0.6,
},
horizontal = {
prompt_position = 'top',
preview_width = 0.6,
height = 0.9,
width = 0.9,
},
cursor = {
width = 0.6,
height = function(self, _, max_lines)
local results, PADDING = #self.finder.results, 4 -- this represents the size of the telescope window
local LIMIT = math.floor(max_lines / 2)
return (results <= (LIMIT - PADDING) and results + PADDING or LIMIT)
end,
},
},
borderchars = borderchars[layout][border_style],
file_ignore_patterns = ignore_patterns,
},
pickers = {
find_files = {
hidden = true,
follow = true,
},
live_grep = {
additional_args = '--hidden',
-- ignore dependencies versions in lock files
file_ignore_patterns = vim.list_extend(vim.list_slice(ignore_patterns), {
'^go%.sum',
'^Cargo%.lock',
'^poetry%.lock',
'^package%-lock%.json',
'^yarn%.lock',
'^pnpm%-lock%.yaml',
'^flake%.lock',
}),
},
registers = {
layout_strategy = 'cursor',
borderchars = borderchars.cursor[border_style],
layout_config = { width = 0.4 },
},
},
extensions = {
file_browser = {
hidden = {
file_browser = true,
folder_browser = true,
},
dir_icon = '󰉋',
},
fzf = { override_generic_sorter = false },
},
}

View File

@ -0,0 +1,22 @@
local nord = {
black = '#2E3440',
grey1 = '#3B4252',
grey2 = '#434C5E',
grey3 = '#4C566A',
grey_bright = '#616E88',
fg = '#D8DEE9',
white1 = '#E5E9F0',
white2 = '#ECEFF4',
teal = '#8FBCBB',
cyan = '#88C0D0',
blue = '#81A1C1',
dark_blue = '#5E81AC',
red = '#BF616A',
orange = '#D08770',
yellow = '#EBCB8B',
green = '#A3BE8C',
purple = '#B48EAD',
highlight = '#7B88A1',
}
return nord

View File

@ -0,0 +1,149 @@
local c = require('user.themes.nord.colors')
return {
Normal = { fg = c.fg },
NormalFloat = { fg = c.fg },
FloatBorder = { fg = c.white2 },
ColorColumn = { bg = c.grey1 },
Cursor = { fg = c.black, bg = c.fg },
CursorIM = { fg = c.black, bg = c.white1 },
CursorLine = { bg = c.grey1 },
TermCursor = { link = 'Cursor' },
TermCursorNC = { bg = c.grey1 },
Underlined = { fg = c.green, underline = true },
Ignore = { fg = c.grey1 },
Error = { fg = c.fg, bg = c.red },
LineNr = { fg = c.grey3 },
MatchParen = { fg = c.cyan, bg = c.grey3 },
NonText = { fg = c.highlight },
Whitespace = { fg = c.highlight },
EndOfBuffer = { fg = c.black }, -- hide filler lines with '~' completely
Pmenu = { fg = c.fg, bg = c.grey1 },
PmenuSbar = { fg = c.fg, bg = c.grey1 },
PmenuSel = { fg = c.cyan, bg = c.grey3, bold = true },
PmenuThumb = { fg = c.cyan, bg = c.grey3, bold = true },
SpecialKey = { fg = c.grey3 },
SperllBad = { fg = c.red, sp = c.red, undercurl = true },
SpellCap = { fg = c.yellow, sp = c.yellow, undercurl = true },
SpellLocal = { fg = c.white1, sp = c.white1, undercurl = true },
SpellRare = { fg = c.white2, sp = c.white2, undercurl = true },
Visual = { bg = c.grey2 },
VisualNOS = { bg = c.grey2 },
-- quickfix
QuickFixLine = { bg = c.grey2 },
qfLineNr = { fg = c.yellow },
-- :checkhealth
healthError = { fg = c.red, bg = c.grey1 },
healthSuccess = { fg = c.green, bg = c.grey1 },
healthWarning = { fg = c.yellow, bg = c.grey1 },
-- gutter
CursorColumn = { bg = c.grey1 },
CursorLineNr = { fg = c.fg },
Folded = { fg = c.highlight, bg = c.grey1 },
FoldColumn = { fg = c.grey3 },
SignColumn = { fg = c.grey1 },
-- navigation
Directory = { fg = c.cyan },
-- prompt
MsgArea = { link = 'Normal' },
ErrorMsg = { fg = c.fg, bg = c.red },
ModeMsg = { fg = c.fg },
MoreMsg = { fg = c.cyan },
Question = { fg = c.fg },
WarningMsg = { fg = c.black, bg = c.yellow },
WildMenu = { fg = c.cyan, bg = c.grey1 },
-- statusline
Statusline = { fg = c.cyan, bg = c.grey1 },
StatusLineNC = { fg = c.fg, bg = c.grey1 },
-- search
IncSearch = { fg = c.white2, bg = c.dark_blue, underline = true },
Search = { fg = c.grey1, bg = c.cyan },
CurSearch = { link = 'IncSearch' },
-- :s/../../
Substitute = { link = 'IncSearch' },
-- tabline
TabLine = { fg = c.fg, bg = c.grey3 },
TabLineFill = { fg = c.fg, bg = c.grey1 },
TabLineSel = { fg = c.black, bg = c.cyan },
-- winbar
WinBar = { fg = c.fg, bg = 'NONE' },
WinBarNC = { link = 'WinBar' },
-- window
Title = { fg = c.fg },
WinSeparator = { fg = c.grey_bright },
-- base syntax
Boolean = { fg = c.blue },
Character = { fg = c.fg },
Comment = { fg = c.grey_bright, italic = true },
Conceal = { fg = 'NONE', bg = 'NONE' },
Conditional = { fg = c.blue, bold = true },
Constant = { fg = c.yellow },
Debug = { fg = c.highlight },
Define = { fg = c.blue },
Delimiter = { fg = c.white2 },
Exception = { fg = c.blue, bold = true },
Float = { fg = c.purple },
Function = { fg = c.cyan },
Identifier = { fg = c.fg },
Include = { fg = c.blue },
Keyword = { fg = c.blue, bold = true },
Label = { fg = c.purple },
Number = { fg = c.purple },
Operator = { fg = c.blue },
PreProc = { fg = c.blue },
Repeat = { fg = c.blue, bold = true },
Special = { fg = c.fg },
SpecialChar = { fg = c.yellow },
SpecialComment = { fg = c.cyan, italic = true },
Statement = { fg = c.blue },
StorageClass = { fg = c.blue },
String = { fg = c.green },
Structure = { fg = c.blue },
Tag = { fg = c.fg },
Todo = { fg = c.yellow },
Type = { fg = c.blue },
Typedef = { fg = c.blue },
Macro = { link = 'Define' },
PreCondit = { link = 'PreProc' },
Variable = { link = 'Identifier' },
-- diff
DiffAdd = { fg = c.green, bg = c.grey1 },
DiffChange = { fg = c.yellow, bg = c.grey1 },
DiffDelete = { fg = c.red, bg = c.grey1 },
DiffText = { fg = c.blue, bg = c.grey1 },
-- NOTE: no TreeSitter grammars yet
-- asciidoc
asciidocAttributeEntry = { fg = c.purple, bold = true },
asciidocAttributeList = { fg = c.purple, bold = true },
asciidocAttributeRef = { fg = c.green, bold = true },
asciidocHLabel = { fg = c.blue },
asciidocListingBlock = { fg = c.teal },
asciidocMacro = { fg = c.green },
asciidocMacroAttributes = { fg = c.purple },
asciidocOneLineTitle = { link = '@text.title' },
asciidocPassthroughBlock = { fg = c.blue },
asciidocTriplePlusPassthrough = { fg = c.teal },
asciidocAdmonition = { link = 'Keyword' },
asciidocBackslash = { link = 'Keyword' },
asciidocQuotedBold = { bold = true },
asciidocQuotedEmphasized = { italic = true },
asciidocQuotedMonospaced = { fg = c.teal },
asciidocQuotedMonospaced2 = { link = 'asciidocQuotedMonospaced' },
asciidocQuotedUnconstrainedBold = { link = 'asciidocQuotedBold' },
asciidocQuotedUnconstrainedEmphasized = { link = 'asciidocQuotedEmphasized' },
asciidocURL = { link = '@text.uri' },
asciidocEmail = { link = '@text.uri' },
}

View File

@ -0,0 +1,72 @@
local c = require('user.themes.nord.colors')
return {
-- LSP semantic tokens
['@lsp.type.boolean'] = { link = '@boolean' },
['@lsp.type.builtinType'] = { link = '@type.builtin' },
['@lsp.type.class'] = { link = '@type' },
['@lsp.type.comment'] = { link = '@comment' },
['@lsp.type.enum'] = { link = '@type' },
['@lsp.type.enumMember'] = { link = '@constant' },
['@lsp.type.escapeSequence'] = { link = '@string.escape' },
['@lsp.type.formatSpecifier'] = { link = '@punctuation.special' },
['@lsp.type.field'] = { link = '@field' },
['@lsp.type.function'] = { link = '@function' },
['@lsp.type.generic'] = { link = '@text' },
['@lsp.type.interface'] = { link = '@type' },
['@lsp.type.keyword'] = { link = '@keyword' },
['@lsp.type.macro'] = { link = '@function.macro' },
['@lsp.type.method'] = { link = '@method' },
['@lsp.type.namespace'] = { link = '@namespace' },
['@lsp.type.number'] = { link = '@number' },
['@lsp.type.operator'] = { link = '@operator' },
['@lsp.type.parameter'] = { link = '@parameter' },
['@lsp.type.property'] = { link = '@property' },
['@lsp.type.selfKeyword'] = { link = '@variable.builtin' },
['@lsp.type.typeAlias'] = { link = '@type.definition' },
['@lsp.type.unresolvedReference'] = { link = '@error' },
['@lsp.type.typeParameter'] = { link = '@parameter' },
['@lsp.type.struct'] = { link = 'Structure' },
['@lsp.type.variable'] = { link = '@variable' },
['@lsp.typemod.enum.defaultLibrary'] = { link = '@type.builtin' },
['@lsp.typemod.enumMember.defaultLibrary'] = { link = '@constant.builtin' },
['@lsp.typemod.function.defaultLibrary'] = { link = '@function.builtin' },
['@lsp.typemod.macro.defaultLibrary'] = { link = '@function.builtin' },
['@lsp.typemod.method.defaultLibrary'] = { link = '@function.builtin' },
['@lsp.typemod.operator.injected'] = { link = '@operator' },
['@lsp.typemod.string.injected'] = { link = '@string' },
['@lsp.typemod.type.defaultLibrary'] = { link = '@type.builtin' },
['@lsp.typemod.variable.defaultLibrary'] = { link = '@variable.builtin' },
['@lsp.typemod.variable.injected'] = { link = '@variable' },
['@lsp.typemod.variable.static'] = { link = '@constant' },
-- LSP
DiagnosticError = { fg = c.red },
DiagnosticWarn = { fg = c.yellow },
DiagnosticInfo = { fg = c.blue },
DiagnosticHint = { fg = c.cyan },
DiagnosticUnderlineError = { sp = c.red, underline = true },
DiagnosticUnderlineWarn = { sp = c.yellow, underline = true },
DiagnosticUnderlineInfo = { sp = c.blue, underline = true },
DiagnosticUnderlineHint = { sp = c.cyan, underline = true },
DiagnosticVirtualTextError = { fg = c.red, italic = true },
DiagnosticVirtualTextWarn = { fg = c.yellow, italic = true },
DiagnosticVirtualTextInfo = { fg = c.blue, italic = true },
DiagnosticVirtualTextHint = { fg = c.cyan, italic = true },
DiagnosticFloatingError = { link = 'DiagnosticError' },
DiagnosticFloatingWarn = { link = 'DiagnosticWarn' },
DiagnosticFloatingInfo = { link = 'DiagnosticInfo' },
DiagnosticFloatingHint = { link = 'DiagnosticHint' },
DiagnosticSignError = { link = 'DiagnosticError' },
DiagnosticSignWarn = { link = 'DiagnosticWarn' },
DiagnosticSignInfo = { link = 'DiagnosticInfo' },
DiagnosticSignHint = { link = 'DiagnosticHint' },
LspReferenceText = { bg = c.grey1 },
LspReferenceRead = { bg = c.grey1 },
LspReferenceWrite = { bg = c.grey1 },
LspCodeLens = { link = 'Comment' },
LspCodeLensSeparator = { fg = c.cyan, italic = true },
LspInlayHint = { link = 'Comment' },
LspSignatureActiveParameter = { bg = c.grey2 },
LspInfoBorder = { link = 'FloatBorder' },
}

View File

@ -0,0 +1,301 @@
local c = require('user.themes.nord.colors')
local util = require('user.util.color')
return {
-- nvim-treesitter-context
TreesitterContext = { bg = c.grey1 },
TreesitterContextLineNumber = { fg = c.fg, bg = c.grey1 },
-- nvim-cmp
CmpItemAbbr = { fg = c.fg },
CmpItemAbbrMatch = { fg = c.yellow, bold = true },
CmpItemAbbrMatchFuzzy = { fg = c.yellow, bold = true },
CmpItemAbbrDeprecated = { fg = c.highlight, strikethrough = true },
CmpItemKind = { fg = c.green, bold = true },
CmpItemMenu = { fg = c.blue, bold = true },
-- tabbyml/tabby
TabbyCompletion = { link = 'Comment' },
-- LuaSnip
LuasnipChoiceNodeActive = { fg = c.orange },
LuasnipInsertNodeActive = { fg = c.blue },
-- gitsigns.nvim
GitSignsAdd = { fg = c.green, bold = true },
GitSignsAddNr = { fg = c.green },
GitSignsAddInline = { fg = c.black, bg = c.green },
GitSignsChange = { fg = c.yellow, bold = true },
GitSignsChangeNr = { fg = c.yellow },
GitSignsChangeInline = { fg = c.black, bg = c.yellow },
GitSignsDelete = { fg = c.red, bold = true },
GitSignsDeleteNr = { fg = c.red },
GitSignsDeleteInline = { fg = c.black, bg = c.red },
GitSignsCurrentLineBlame = { fg = c.grey_bright, bold = true, italic = true },
-- git-conflict.nvim
GitConflictCurrent = { bg = util.blend(c.green, c.black, 0.2) },
GitConflictIncoming = { bg = util.blend(c.blue, c.black, 0.2) },
GitConflictAncestor = { bg = util.blend(c.yellow, c.black, 0.2) },
-- rainbow-delimiters.nvim
RainbowDelimiterRed = { fg = c.red, bold = true },
RainbowDelimiterOrange = { fg = c.orange, bold = true },
RainbowDelimiterYellow = { fg = c.yellow, bold = true },
RainbowDelimiterGreen = { fg = c.green, bold = true },
RainbowDelimiterCyan = { fg = c.cyan, bold = true },
RainbowDelimiterBlue = { fg = c.blue, bold = true },
RainbowDelimiterViolet = { fg = c.purple, bold = true },
-- dashboard.nvim / alpha-nvim
DashboardHeader = { fg = c.cyan, bold = true },
DashboardCenter = { fg = c.blue, bold = true },
DashboardShortcut = { fg = c.green, bold = true },
DashboardFooter = { fg = c.yellow, bold = true },
-- nvim-tree.lua
NvimTreeNormal = { fg = c.fg },
NvimTreeIndentMarker = { fg = c.grey3 },
NvimTreeFolderIcon = { fg = c.fg },
NvimTreeRootFolder = { fg = c.teal, bold = true },
NvimTreeFolderName = { fg = c.blue },
NvimTreeEmptyFolderName = { fg = c.grey_bright },
NvimTreeImageFile = { fg = c.yellow },
NvimTreeExecFile = { fg = c.green },
NvimTreeSpecialFile = { fg = c.cyan, underline = true },
NvimTreeGitDirty = { fg = c.yellow },
NvimTreeGitDeleted = { fg = c.red },
NvimTreeWindowPicker = { fg = c.white2, bg = c.blue, bold = true },
-- which-key.nvim
WhichKey = { fg = c.green, bold = true },
WhichKeyGroup = { fg = c.cyan },
WhichKeyDesc = { fg = c.blue },
WhichKeySeparator = { fg = c.grey_bright },
WhichKeyFloat = { link = 'NormalFloat' },
WhichKeyValue = { link = 'Comment' },
-- nvim-notify
NotifyERRORBorder = { fg = c.red },
NotifyWARNBorder = { fg = c.yellow },
NotifyINFOBorder = { fg = c.blue },
NotifyDEBUGBorder = { fg = c.green },
NotifyTRACEBorder = { fg = c.white2 },
NotifyERRORIcon = { link = 'NotifyERRORBorder' },
NotifyWARNIcon = { link = 'NotifyWARNBorder' },
NotifyINFOIcon = { link = 'NotifyINFOBorder' },
NotifyDEBUGIcon = { link = 'NotifyDEBUGBorder' },
NotifyTRACEIcon = { link = 'NotifyTRACEBorder' },
NotifyERRORTitle = { link = 'NotifyERRORBorder' },
NotifyWARNTitle = { link = 'NotifyWARNBorder' },
NotifyINFOTitle = { link = 'NotifyINFOBorder' },
NotifyDEBUGTitle = { link = 'NotifyDEBUGBorder' },
NotifyTRACETitle = { link = 'NotifyTRACEBorder' },
NotifyERRORBody = { link = 'Normal' },
NotifyWARNBody = { link = 'Normal' },
NotifyINFOBody = { link = 'Normal' },
NotifyDEBUGBody = { link = 'Normal' },
NotifyTRACEBody = { link = 'Normal' },
-- nvim-scrollbar
ScrollbarHandle = { bg = c.grey1 },
ScrollbarError = { fg = c.red, bold = true },
ScrollbarErrorHandle = { fg = c.red, bg = c.grey1, bold = true },
ScrollbarWarn = { fg = c.yellow, bold = true },
ScrollbarWarnHandle = { fg = c.yellow, bg = c.grey1, bold = true },
ScrollbarInfo = { fg = c.blue, bold = true },
ScrollbarInfoHandle = { fg = c.blue, bg = c.grey1, bold = true },
ScrollbarHint = { fg = c.cyan, bold = true },
ScrollbarHintHandle = { fg = c.cyan, bg = c.grey1, bold = true },
ScrollbarMisc = { fg = c.white2, bold = true },
ScrollbarMiscHandle = { fg = c.white2, bg = c.grey1, bold = true },
-- indent-blankline.nvim
IblIndent = { fg = c.grey1 },
IblScope = { fg = c.grey_bright },
-- headlines.nvim
-- NOTE: keep bg of these in sync with OrgHeadlineLevel{1..6}
Headline1 = { bg = util.blend(c.purple, c.black, 0.09), bold = true },
Headline2 = { bg = util.blend(c.blue, c.black, 0.09), bold = true },
Headline3 = { bg = util.blend(c.green, c.black, 0.09), bold = true },
Headline4 = { bg = util.blend(c.yellow, c.black, 0.09), bold = true },
Headline5 = { bg = util.blend(c.orange, c.black, 0.09), bold = true },
Headline6 = { bg = util.blend(c.fg, c.black, 0.09), bold = true },
Quote = { fg = c.grey_bright },
CodeBlock = { bg = c.grey1 },
Dash = { fg = c.blue, bold = true },
-- nvim-orgmode
OrgHeadlineLevel1 = { fg = c.purple, bold = true },
OrgHeadlineLevel2 = { fg = c.blue, bold = true },
OrgHeadlineLevel3 = { fg = c.green, bold = true },
OrgHeadlineLevel4 = { fg = c.yellow, bold = true },
OrgHeadlineLevel5 = { fg = c.orange, bold = true },
OrgHeadlineLevel6 = { fg = c.fg, bold = true },
OrgTODO = { fg = c.green, bold = true },
OrgDONE = { fg = c.purple, bold = true },
OrgTSCheckbox = { link = '@text.todo.unchecked' },
OrgTSCheckboxChecked = { link = '@text.todo.checked' },
OrgTSCheckboxHalfChecked = { fg = c.blue, bold = true },
OrgAgendaDealine = { fg = c.red, bold = true },
OrgAgendaScheduled = { fg = c.green, bold = true },
OrgAgendaScheduledPast = { fg = c.blue, bold = true },
-- sniprun.nvim
SniprunVirtualTextOk = { bg = c.cyan, fg = c.black },
SniprunFloatingWinOk = { fg = c.cyan },
SniprunVirtualTextErr = { bg = c.orange, fg = c.black },
SniprunFloatingWinErr = { fg = c.orange },
-- trouble.nvim
LspTroubleText = { fg = c.blue, bold = true },
-- telescope.nvim
TelescopeBorder = { fg = c.cyan },
TelescopeTitle = { fg = c.black, bg = c.cyan, bold = true },
TelescopeSelection = { fg = c.fg, bg = c.grey1 },
TelescopeMultiSelection = { fg = c.fg, bg = c.grey1, bold = true },
TelescopeSelectionCaret = { fg = c.red, bg = c.grey1, bold = true },
TelescopeMatching = { fg = c.yellow, bold = true },
-- overseer.nvim
OverseerPENDING = { fg = c.purple, bold = true },
OverseerRUNNING = { fg = c.blue, bold = true },
OverseerSUCCESS = { fg = c.green, bold = true },
OverseerCANCELED = { fg = c.yellow, bold = true },
OverseerFAILURE = { fg = c.red, bold = true },
OverseerTask = { fg = c.cyan },
OverseerComponent = { fg = c.yellow },
OverseerField = { fg = c.green },
-- neogit
NeogitBranch = { fg = c.purple, bold = true },
NeogitRemote = { fg = c.green, bold = true },
NeogitObjectId = { fg = c.teal },
NeogitStash = { link = 'Comment' },
NeogitFold = { fg = c.highlight, bold = true },
NeogitRebaseDone = { link = 'Comment' },
NeogitTagName = { link = 'NeogitBranch' },
NeogitTagDistance = { fg = c.red, bold = true },
NeogitSectionHeader = { fg = c.blue, bold = true },
NeogitChangeModified = { fg = c.cyan, bold = true },
NeogitChangeAdded = { fg = c.green, bold = true },
NeogitChangeDeleted = { fg = c.red, bold = true },
NeogitChangeRenamed = { fg = c.purple, bold = true },
NeogitChangeUpdated = { fg = c.cyan, bold = true },
NeogitChangeCopied = { fg = c.blue, bold = true },
NeogitChangeBothModified = { fg = c.yellow, bold = true },
NeogitChangeNewFile = { fg = c.green, bold = true },
NeogitHunkHeader = { fg = c.yellow, bold = true },
NeogitHunkHeaderHighlight = { fg = c.yellow, bg = util.blend(c.yellow, c.black, 0.09), bold = true },
NeogitDiffContext = { fg = c.blue },
NeogitDiffContextHighlight = { fg = c.blue, bg = util.blend(c.blue, c.black, 0.09) },
NeogitDiffAdd = { fg = c.green },
NeogitDiffAddHighlight = { fg = c.green, bg = util.blend(c.green, c.black, 0.09) },
NeogitDiffDelete = { fg = c.red },
NeogitDiffDeleteHighlight = { fg = c.red, bg = util.blend(c.red, c.black, 0.09) },
NeogitDiffHeader = { fg = c.purple, bold = true },
NeogitDiffHeaderHighlight = { fg = c.purple, bg = util.blend(c.purple, c.black, 0.09), bold = true },
NeogitCursorLine = { link = 'CursorLine' },
NeogitFilePath = { fg = c.teal, bold = true },
NeogitCommitViewHeader = { fg = c.white2, bg = c.dark_blue, bold = true },
NeogitGraphBlack = { fg = c.grey2 },
NeogitGraphBlackBold = { fg = c.grey2, bold = true },
NeogitGraphRed = { fg = c.red },
NeogitGraphRedBold = { fg = c.red, bold = true },
NeogitGraphGreen = { fg = c.green },
NeogitGraphGreenBold = { fg = c.green, bold = true },
NeogitGraphYellow = { fg = c.yellow },
NeogitGraphYellowBold = { fg = c.yellow, bold = true },
NeogitGraphBlue = { fg = c.blue },
NeogitGraphBlueBold = { fg = c.blue, bold = true },
NeogitGraphPurple = { fg = c.purple },
NeogitGraphPurpleBold = { fg = c.purple, bold = true },
NeogitGraphCyan = { fg = c.cyan },
NeogitGraphCyanBold = { fg = c.cyan, bold = true },
NeogitGraphWhite = { fg = c.white2 },
NeogitGraphWhiteBold = { fg = c.white2, bold = true },
NeogitGraphGray = { fg = c.highlight },
NeogitGraphGrayBold = { fg = c.highlight, bold = true },
NeogitGraphOrange = { fg = c.orange },
NeogitSignatureGood = { fg = c.green, bold = true },
NeogitSignatureBad = { fg = c.red, bold = true },
NeogitSignatureMissing = { fg = c.yellow, bold = true },
NeogitSignatureNone = { link = 'NeogitObjectId' },
NeogitSignatureGoodUnknown = { fg = c.green, italic = true },
NeogitSignatureGoodExpired = { link = 'NeogitSignatureGoodUnknown' },
NeogitSignatureGoodExpiredKey = { link = 'NeogitSignatureGoodUnknown' },
NeogitSignatureGoodRevokedKey = { fg = c.cyan, bold = true },
NeogitNotificationInfo = { link = 'NotifyINFOTitle' },
NeogitNotificationWarning = { link = 'NotifyWARNTitle' },
NeogitNotificationError = { link = 'NotifyERRORTitle' },
NeogitPopupSectionTitle = { fg = c.blue, bold = true },
NeogitPopupBranchName = { link = 'NeogitBranch' },
NeogitPopupBold = { link = '@text.strong' },
NeogitPopupSwitchKey = { fg = c.green },
NeogitPopupSwitchEnabled = { link = 'Comment' },
NeogitPopupSwitchDisabled = { fg = c.yellow, italic = true },
NeogitPopupOptionKey = { link = 'NeogitPopupSwitchKey' },
NeogitPopupOptionEnabled = { link = 'NeogitPopupSwitchEnabled' },
NeogitPopupOptionDisabled = { link = 'NeogitPopupSwitchDisabled' },
NeogitPopupConfigKey = { link = 'NeogitPopupSwitchKey' },
NeogitPopupConfigEnabled = { link = 'NeogitPopupSwitchEnabled' },
NeogitPopupConfigDisabled = { link = 'NeogitPopupSwitchDisabled' },
NeogitPopupActionKey = { link = 'NeogitPopupSwitchKey' },
NeogitPopupActionEnabled = { link = 'NeogitPopupSwitchEnabled' },
NeogitPopupActionDisabled = { link = 'NeogitPopupSwitchDisabled' },
-- flash.nvim
FlashBackdrop = { fg = c.grey_bright },
FlashMatch = { fg = c.white2, bold = true },
FlashLabel = { fg = c.white2, bg = c.red, bold = true },
-- nvim-navic
NavicText = { link = 'Normal' },
NavicSeparator = { fg = c.cyan },
-- nvim-coverage
CoverageCovered = { fg = c.green },
CoverageUncovered = { fg = c.red },
CoveragePartial = { fg = c.yellow },
CoverageSummaryHeader = { fg = c.purple, bold = true },
CoverageSummaryPass = { fg = c.green, bold = true },
CoverageSummaryFail = { fg = c.red, bold = true },
-- neotest
NeotestPassed = { fg = c.green },
NeotestFailed = { fg = c.red },
NeotestRunning = { fg = c.yellow },
NeotestSkipped = { fg = c.cyan },
NeotestNamespace = { fg = c.red, bold = true },
NeotestFile = { fg = c.cyan },
NeotestDir = { link = 'NeotestFile' },
NeotestIndent = { link = 'NvimTreeIndentMarker' },
NeotestExpandMarker = { link = 'NvimTreeIndentMarker' },
NeotestAdapterName = { fg = c.purple },
NeotestWinSelect = { fg = c.cyan, bold = true },
NeotestMarked = { fg = c.blue, bold = true },
NeotestTarget = { fg = c.red },
NeotestWatching = { fg = c.yellow },
-- lazy.nvim
LazyDimmed = { link = 'Normal' },
LazyProp = { fg = c.highlight, bold = true },
LazyH1 = { fg = c.white2, bg = c.dark_blue, bold = true },
LazyH2 = { fg = c.purple, bold = true },
LazyButton = { fg = c.white2, bg = c.grey1 },
LazyButtonActive = { link = 'LazyH1' },
LazySpecial = { fg = c.white2 },
LazyCommit = { fg = c.teal },
LazyReasonImport = { fg = c.teal },
LazyReasonRuntime = { fg = c.green },
LazyReasonCmd = { fg = c.cyan, bold = true },
LazyReasonEvent = { fg = c.yellow, bold = true },
LazyReasonFt = { fg = c.purple, bold = true },
LazyReasonKeys = { fg = c.green, bold = true },
LazyReasonPlugin = { fg = c.blue, bold = true },
LazyReasonRequire = { fg = c.teal, bold = true },
LazyReasonSource = { fg = c.red, bold = true },
LazyReasonStart = { fg = c.orange, bold = true },
}

View File

@ -0,0 +1,82 @@
local c = require('user.themes.nord.colors')
-- :help nvim-treesitter-highlights
return {
['@annotation'] = { fg = c.blue, italic = true },
['@attribute'] = { fg = c.purple },
['@boolean'] = { link = 'Boolean' },
['@character'] = { link = 'Character' },
['@character.special'] = { link = 'SpecialChar' },
['@comment'] = { link = 'Comment' },
['@conditional'] = { link = 'Conditional' },
['@constant'] = { link = 'Constant' },
['@constant.builtin'] = { fg = c.teal },
['@constant.macro'] = { fg = c.teal },
['@conceal'] = { link = 'Conceal' },
['@constructor'] = { fg = c.blue },
['@debug'] = { link = 'Debug' },
['@define'] = { link = 'Define' },
['@error'] = { fg = c.red },
['@exception'] = { link = 'Exception' },
['@field'] = { fg = c.teal },
['@float'] = { link = 'Float' },
['@function'] = { link = 'Function' },
['@function.call'] = { link = 'Function' },
['@function.builtin'] = { link = 'Function' },
['@function.macro'] = { fg = c.teal },
['@include'] = { link = 'Include' },
['@keyword'] = { link = 'Keyword' },
['@keyword.function'] = { link = 'Keyword' },
['@keyword.return'] = { link = 'Keyword' },
['@keyword.operator'] = { link = 'Keyword' },
['@label'] = { link = 'Label' },
['@method'] = { fg = c.teal },
['@method.call'] = { fg = c.teal, bold = true },
['@namespace'] = { fg = c.white1 },
-- ['@none'] = { fg = 'NONE', bg = 'NONE' },
['@number'] = { link = 'Number' },
['@operator'] = { link = 'Operator' },
['@parameter'] = { fg = c.purple, italic = true },
['@parameter.reference'] = { fg = c.purple, italic = true },
['@preproc'] = { link = 'PreProc' },
['@property'] = { fg = c.teal },
['@punctuation.delimiter'] = { link = 'Delimiter' },
['@punctuation.bracket'] = { link = 'Delimiter' },
['@punctuation.special'] = { link = 'Delimiter' },
['@repeat'] = { link = 'Repeat' },
['@storageclass'] = { link = 'StorageClass' },
['@string'] = { link = 'String' },
['@string.regex'] = { fg = c.teal },
['@string.escape'] = { fg = c.purple },
['@string.special'] = { link = 'Special' },
['@symbol'] = { fg = c.purple },
['@tag'] = { link = 'Tag' },
['@tag.attribute'] = { fg = c.orange, italic = true },
['@tag.delimiter'] = { fg = c.purple },
['@text'] = { link = 'Normal' },
['@text.diff.add'] = { link = 'DiffAdd' },
['@text.diff.delete'] = { link = 'DiffDelete' },
['@text.strong'] = { bold = true },
['@text.emphasis'] = { italic = true },
['@text.underline'] = { underline = true },
['@text.strike'] = { strikethrough = true },
['@text.title'] = { fg = c.cyan, bold = true },
['@text.literal'] = { fg = c.green, italic = true },
['@text.uri'] = { fg = c.green, underline = true },
['@text.math'] = { fg = c.yellow },
['@text.reference'] = { fg = c.purple, italic = true },
['@text.environment'] = { fg = c.cyan },
['@text.environment.name'] = { fg = c.purple, bold = true },
['@text.todo'] = { link = 'Todo' },
['@text.note'] = { fg = c.blue, bold = true },
['@text.warning'] = { fg = c.yellow, bold = true },
['@text.danger'] = { fg = c.red, bold = true },
['@text.todo.unchecked'] = { fg = c.blue, bold = true },
['@text.todo.checked'] = { fg = c.green, bold = true },
['@type'] = { link = 'Type' },
['@type.builtin'] = { link = 'Type' },
['@type.qualifier'] = { fg = c.blue, bold = true, italic = true },
['@type.definition'] = { link = 'Typedef' },
['@variable'] = { link = 'Variable' },
['@variable.builtin'] = { link = 'Variable' },
}

View File

@ -0,0 +1,31 @@
local M = {}
local c = require('user.themes.nord.colors')
M.termcolors = {
c.grey1,
c.red,
c.green,
c.yellow,
c.blue,
c.purple,
c.cyan,
c.white1,
c.grey_bright,
c.red,
c.green,
c.yellow,
c.blue,
c.purple,
c.teal,
c.white2,
}
M.highlights = vim.tbl_extend(
'force',
require('user.themes.nord.groups.editor'),
require('user.themes.nord.groups.treesitter'),
require('user.themes.nord.groups.lsp'),
require('user.themes.nord.groups.plugins')
)
return M

View File

@ -0,0 +1,23 @@
local onedark = {
black = '#282C34',
grey1 = '#3E4452',
grey2 = '#4B5263',
grey3 = '#5C6470',
grey_bright = '#73797E',
fg = '#ABB2BF',
white1 = '#BBC2CF',
white2 = '#DFDFDF',
teal = '#5699AF',
cyan = '#56B6C2',
blue = '#61AFEF',
dark_blue = '#2257A0',
red = '#E06C75',
dark_red = '#BE5046',
orange = '#D19A66',
yellow = '#E5C07B',
green = '#98C379',
purple = '#C678DD',
highlight = '#9CA0A4',
}
return onedark

View File

@ -0,0 +1,3 @@
local M = {}
return M

82
lua/user/util/color.lua Normal file
View File

@ -0,0 +1,82 @@
local M = {}
--- Convert Hexadecimal color string to list of decimal Red, Green, Blue values
---@param color string e.g. '#2e3440'
---@return table
local function hex2rgb(color)
color = string.lower(color)
return {
tonumber(color:sub(2, 3), 16),
tonumber(color:sub(4, 5), 16),
tonumber(color:sub(6, 7), 16),
}
end
--- Lighten/Darken the colors with the amount provided
---@param hex string e.g. '#2e3440'
---@param alpha number a number in the range [-1, 1]
---@return string
function M.shade(hex, alpha)
vim.validate {
percent = { alpha, function(arg) return -1 <= arg and arg <= 1 end, 'a number in the range [-1, 1]' }
}
local rgb = hex2rgb(hex)
local function shadeChannel(i)
return math.min(math.floor(math.max(0, rgb[i] * (1 + alpha))), 255)
end
return string.format('#%02x%02x%02x', shadeChannel(1), shadeChannel(2), shadeChannel(3))
end
---@param foreground string foreground color
---@param background string background color
---@param alpha number number within range [-1, 1]
function M.blend(foreground, background, alpha)
vim.validate {
percent = { alpha, function(arg) return -1 <= arg and arg <= 1 end, 'a number in the range [-1, 1]' }
}
local fg = hex2rgb(foreground)
local bg = hex2rgb(background)
local blendChannel = function(i)
local ret = (alpha * fg[i] + (1 - alpha) * bg[i])
return math.floor(math.min(math.max(0, ret), 255) + 0.5)
end
return string.format('#%02x%02x%02x', blendChannel(1), blendChannel(2), blendChannel(3))
end
function M.darken(hex, alpha, bg)
return M.blend(hex, alpha, bg or '#000000')
end
function M.lighten(hex, alpha, fg)
return M.blend(hex, alpha, fg or '#ffffff')
end
--- Load defined Neovim theme inside lua/user/themes/ and setup highlights
---@param theme string
function M.load_theme(theme)
-- Reset
if vim.g.colors_name then
vim.cmd('highlight clear')
end
-- Get theme specs
vim.g.colors_name = theme
local t = require('user.themes.' .. theme)
-- Set base16 terminal colors
for index, val in ipairs(t.termcolors) do
vim.g['terminal_color_' .. (index - 1)] = val
end
-- Load highlight groups
for group, val in pairs(t.highlights) do
vim.api.nvim_set_hl(0, group, val)
end
end
return M

37
lua/user/util/lsp.lua Normal file
View File

@ -0,0 +1,37 @@
local M = {}
--- Return the list of active LSP clients
---@return table
function M.lsp_active_clients()
local clients = {}
for _, client in ipairs(vim.lsp.get_active_clients { bufnr = 0 }) do
table.insert(clients, client.name)
end
return clients
end
-- Re-implement nvim-lightbulb naively
-- Update status text indicating whether a CodeAction exists at cursor position
function M.codeAction_on_attach()
local params = vim.lsp.util.make_range_params()
params.context = { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() }
vim.lsp.buf_request_all(0, 'textDocument/codeAction', params, function(responses)
local has_actions = false
for _, resp in pairs(responses) do
if resp.result and not vim.tbl_isempty(resp.result) then
has_actions = true
break
end
end
if has_actions then
vim.b.has_code_action_text = '󰌵 Code action'
else
vim.b.has_code_action_text = nil
end
end)
end
return M

52
lua/user/util/misc.lua Normal file
View File

@ -0,0 +1,52 @@
local M = {}
function M.buffer_not_empty()
if vim.fn.empty(vim.fn.expand('%:t')) ~= 1 then
return true
end
return false
end
---@param plugin string
---@return boolean
function M.has(plugin)
return require('lazy.core.config').plugins[plugin] ~= nil
end
--- Switch between defined values of an option
---@param silent boolean?
---@param values? {[1]:any, [2]:any}
function M.toggle(option, silent, values)
local util = require('lazy.core.util')
if values then
if vim.opt_local[option]:get() == values[1] then
vim.opt_local[option] = values[2]
else
vim.opt_local[option] = values[1]
end
return util.info('Set ' .. option .. ' to ' .. vim.opt_local[option]:get(), { title = 'Vim option' })
end
vim.opt_local[option] = not vim.opt_local[option]:get()
if not silent then
if vim.opt_local[option]:get() then
util.info('Enabled ' .. option, { title = 'Vim option' })
else
util.warn('Disabled ' .. option, { title = 'Vim option' })
end
end
end
--- Return the 1st found matched file/directory names
---@param files string|string[]
---@return fun(src: string): nil|string
function M.root_has_file(files)
return function(src)
local found = vim.fs.find(files, { upward = true, path = src })[1]
if found then
return vim.fs.dirname(found)
end
end
end
return M

Some files were not shown because too many files have changed in this diff Show More