Detailed changes
@@ -6,85 +6,86 @@ Xft.hinting: 1
Xft.antialias: 1
Xft.rgba: rgb
-! Xresources has a base colour and a bright variant. The first block contains
-! the base colours and the second block contains their bright counterparts.
+! Xresources has a base colour and a bright variant. The first of each colour
+! pair is "dark" and the second is "bright". In the context of most shell
+! themes, "dark" variants seem to be used as foreground accents, while "light"
+! variants are highlights behind the default foreground colour.
-{{- if eq .theme_variant "dark" }}
-! Catppuccin Macchiato
-! https://github.com/catppuccin/xresources
+{{ if eq .theme_variant "dark" -}}
+! Everforest hard dark
+! https://github.com/sainnhe/everforest/blob/master/palette.md
-*background: #24273A
-*foreground: #CAD3F5
+*background: #272E33
+*foreground: #D3C6AA
! black
-*color0: #494D64
-*color8: #5B6078
+*color0: #1E2326
+*color8: #7A8478
! red
-*color1: #ED8796
-*color9: #ED8796
+*color1: #E67E80
+*color9: #E67E80
! green
-*color2: #A6DA95
-*color10: #A6DA95
+*color2: #A7C080
+*color10: #A7C080
! yellow
-*color3: #EED49F
-*color11: #EED49F
+*color3: #DBBC7F
+*color11: #DBBC7F
! blue
-*color4: #8AADF4
-*color12: #8AADF4
+*color4: #7FBBB3
+*color12: #7FBBB3
! magenta
-*color5: #F5BDE6
-*color13: #F5BDE6
+*color5: #D699B6
+*color13: #D699B6
! cyan
-*color6: #8BD5CA
-*color14: #8BD5CA
+*color6: #7FBBB3
+*color14: #7FBBB3
! white
-*color7: #B8C0E0
-*color15: #A5ADCB
+*color7: #D3C6AA
+*color15: #D3C6AA
{{- end }}
-{{- if eq .theme_variant "light" }}
+{{ if eq .theme_variant "light" -}}
+! Everforest soft light
+! https://github.com/sainnhe/everforest/blob/master/palette.md
-! Catppuccin Latte
-! https://github.com/catppuccin/xresources
-
-*background: #EFF1F5
-*foreground: #4C4F69
+*background: #F3EAD3
+*foreground: #5C6A72
! black
*color0: #5C5F77
-*color8: #6C6F85
+*color8: #939f91
! red
-*color1: #D20F39
-*color9: #D20F39
+*color1: #F85552
+*color9: #F85552
! green
-*color2: #40A02B
-*color10: #40A02B
+*color2: #8DA101
+*color10: #8DA101
! yellow
-*color3: #DF8E1D
-*color11: #DF8E1D
+*color3: #DFA000
+*color11: #DFA000
! blue
-*color4: #1E66F5
-*color12: #1E66F5
+*color4: #3A94C5
+*color12: #3A94C5
! magenta
-*color5: #EA76CB
-*color13: #EA76CB
+*color5: #DF69BA
+*color13: #DF69BA
! cyan
-*color6: #179299
-*color14: #179299
+*color6: #3A94C5
+*color14: #3A94C5
! white
-*color7: #ACB0BE
-*color15: #BCC0CC
+*color7: #708089
+*color15: #708089
{{- end }}
@@ -16,7 +16,7 @@ decorations = "None"
padding = { x = 7, y = 5 }
[font]
-normal = { family = "Berkeley Mono", style = "Regular" }
+normal = { family = "{{ .font }}", style = "Regular" }
[cursor]
style = { blinking = "On" }
@@ -13,7 +13,8 @@
(load-theme 'everforest-hard-dark t)
{{- end }}
{{- if eq .theme_variant "light"}}
-(load-theme 'everforest-soft-light t)
+;;(load-theme 'everforest-soft-light t)
+(load-theme 'doom-flatwhite t)
{{- end }}
(setq display-line-numbers-type t)
@@ -145,7 +146,7 @@
(setq tidal-boot-script-path "/usr/share/x86_64-linux-ghc-9.0.2/tidal-1.7.10/BootTidal.hs")
-(global-tree-sitter-mode)
+(setq +tree-sitter-hl-enabled-modes '(not fundamental-mode))
(add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode)
(global-wakatime-mode)
@@ -1,196 +1,194 @@
-----BEGIN AGE ENCRYPTED FILE-----
-YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEhBV2NqUSBBbkdSeDhT
-V3U5R1NiRlFHOERTKzJUODZ5WXQ1ZnFnWGhMeUZzTDV4R2JzeQpZS2I4UzhxOGxh
-TzF0STZoNVpFVkdnOGNGMldHQkZkY3ZBaE14SFhQQkI0Ci0+IHBpdi1wMjU2IHBE
-YXpSZyBBMG91U0RjeC9iRE9qZjQ5eWg2cnp3bFZ1SHUwbDhHL0NLa0NrL0xtNzZ1
-MwpWM2J4cU01ZlZnUldkajdwQjBUWlFDMHk4RzZYcXJ3R0lQd1IyWHRxZEVRCi0+
-IHJOYWN3Jy1ncmVhc2UgdVs6ID51UgprcVZoVlgrYlgyRWVSN1ppWmZsMDBaMDFJ
-bWdqTm16SGNvNHFRcDBFOE0yQmdORGVSNFVGUlV6ejc2SHRaSEhJCmxkcXdvaDly
-VFc1RkxaUWZ3bkRoV2V3YmtOcXhhNTRYV2tZawotLS0gblZqK1RBOUEySmp4ci9B
-SWxyZFlZNnUzLzZDWHdNM2ZzY0lZU09pZENEcwpIYQ5Hy0EvpPoEymKQdwB3Kzwo
-lvE3EYzgWpxHkpiemxwngKE0wB32swTQpiWM/7XRCqZ2lNqY38lzuthz0SyQtGOE
-elCIMfi6uB5MUQICai9MnDYx//wOoODJZDRKqhLfjdDb4oRRdZWxbevcGCqu1tr5
-x80fEzwTDAM68Rui+BGii72AAYmVBYZJBSBxAQfH/XjhKP2wYF6OZcVQ3tABosvz
-Ro6SkXZnhy10/PzNCIC+yYOHZsAGEMTD5mOdGTT6FyIumAOfTIo1LnC4OTOcrqpz
-5TiYvp78admTAQniIGVTk+p5yGH0LBQ7R6LA5RTVHQcOD17fKizOb0VqYQAhfXWI
-WT2ayCfyhY6YpY7o56/R89tSUW+i/QO9d6DuQjEC1t7qZ0+XGlF+139trGFXj83R
-wP0r++7SMh1DwwAlfRfWk51/SgGrtueSdVPd0M1OgLGL7M+PIMVqV4Iasunwry8X
-cDGJSzxPENbe3SUZbmfAXpERZcnm5DB8U8ZW1Tf8gbLCz3q/zHTenf05VHIc8e9Z
-82UxWKdC9uw9/ESe3nmoX2MeeI8OCXyNNe1TxohGlag/3QF5Auto4rxm4Q3Kt8un
-xZfEy2ujtnpuF1gdhhdPNGmJ0U/lhrUwh8huj7SuunYQDZ1dkH1vd2R5jKQRBzoo
-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
-ufHjZUKZaDwFEBf+UPmEcYZxUetDdYUla4OE2W9lJWiuZAkIYudUHLsWrCCnVSVM
-+zWl4SDbXAQcaBRE6pa5q9v0qKNpwezcnu5X4+sTXPN76J5C2NnmtKYHZdRk1b+T
-RteTlC1nC4CoXin47n/99hVORWpMYB6wlZFeNLqUJrH1KPLI7haCWU6z4CMR0ZGX
-X2V/mz1FZkIFCaqieJuAw3CurpLbkB/4AtUVv8HabHc/rR+Tog==
+YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEhBV2NqUSBBLy84L0s1
+YlJKMm5YMGM4WFBJYUtOUFpCV0VOUitHbnRwL2JnaTNsRXRzNwpTbjRFU0lhRkxz
+REMwUzQyQWlpbFlDbXh4YmQ2QVdUQVRLYzB0UTlVT25ZCi0+IHBpdi1wMjU2IHBE
+YXpSZyBBekVjeDVqSDdtVTVZb29JYkpxTnVWaGdLdGYyenB2OTJGQjVUNGxXc3hq
+cApyejR1bUpocVBQOGF5N3cyOEtycGkwdjIxM0tHUVpnWXJObWxXVjR5bVlRCi0+
+IFB0bkAqMS1ncmVhc2UKZk9ST3RnTHlaRmlVWEEKLS0tIEZLaFAyendSeWI5dVQ4
+ZXE5dEdnbzdkZ3FiTyt1QXdEaGxOaWJRQUZNV2sKfeYlywwJPzsS2U8Y6IPh+/k+
+SPOzJiGHn0cXF1iyCM+r//bU0Pw0hE44I1H9IZBrdYwiN9UuYAJLZKaq8PervLl9
+va2wYQGHtTTsSrRA0pprQ+4NbHZI+Bx7Y70PZCLk3nK5Z+yZTVdXVXTKmJTCfiX6
+RZkc6kJJaX14aKsdDdIrjTmavZX1qTdTFYTJGXq3hVOwTdvMELimTLVPZkwAE9Ng
+Wt4ZzFqsFEEE1Cfau2wQgtYwHXqtywyMs68MyzZzTP5EWjetkX8SoSLPByTFiya6
+wIcHchM6Er7Dq3zAuCSQeGro+BcxTtsLqpn+UpBYc9Y4e4Q156DKdTtyB1jmBkLe
+izDXkt6St7mKdGH3odvpyi1wNuG8yroM7RqVeyF0tA/4s46Z1OPYbL6YbKkX8LM/
+A438QSXY+RtFt1dYvjzIHwh1lfnzE8gCNTWZjMQfiXYGZA/zdLiEus9PFuAsoZtf
+X55fGeNP8vPdV95cPt04vO+dXK1cNge8Nq5BUuZVY9ASOAfSVPCicdoE7lvk6bxX
+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
-----END AGE ENCRYPTED FILE-----
@@ -1,29 +1,26 @@
-----BEGIN AGE ENCRYPTED FILE-----
-YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEhBV2NqUSBBbThZUVRt
-bmIzbk1KS0c5K3ZJZlNkcW16dkc4RjlrZG80QkVndlVydk5oOQpYQjZsd0ttMXB5
-WVVGQ1NSTCtyeE5US3ZtVGpzYnQ5MXZyaWxQTGFWS3VVCi0+IHBpdi1wMjU2IHBE
-YXpSZyBBbDRJQWlZTm1pRlJLN1N2SEVYc0prYkZUN0RSWkVjbnB0VGxBYU9mK2JX
-eApaeS9yWmpoQnFKaFhtQ2dPTjR1S0trQVJjZlhFanRBNUZadWJBUUpMSDUwCi0+
-IFNPMW4tZ3JlYXNlIDEqOickSiEgXCRGXyBVMkZXIH41ZUAkTApOZzlsRk02ZjdK
-QitVMXR2SXg2ZWtrcjVxSE5WSHd3M2xyaTdKT0M3dVUvR1NaOEFBN2YwOHpnUFBr
-VmFUVG5ECm1IVGpPMWFPd0gweWRWa0xNc3E5K0dxQnRnRUIvU3AwUTVpd0J2dE40
-SzhaRXNWeTRPMWdzby9YSVhRVgotLS0gOUZxb3A5c3ZtWXczbXVkTXRwNGlLYVUv
-dCtzMzUycHlRV2lyU2hpcVg5WQogH7jv9knJvy/XUG3/78RGg0DjBAwDhdha5Opl
-Wwjs/9qLPFYgKW4kUVW7HqlJ10YrYOaJvquK77a1o1mA1aYE4Qw6vD8NbxATuNNk
-Ykrthjhu8wioOrRZtMB1rKAcl1GaBH6S/jsZrp7K6wNXYH3fYx/1AW+QN0INTS4f
-CSX0VQwskQunNcUKcmNmyzaeitFkyKeBmPkUddNAleE4ulQ5NLeHsYzNPR3eE9JD
-fvWa3KvzMLzxbrvS1pBqFL+cHBPWDiKjFuXMGAxnbSIWd08JAg3vRZ/lWI55/+3z
-frRieXSYOvlAw1/UoT1jbMoUYSwhunDDh9OWOT16YM72tlpXRTFfVbh4mxKYWTk0
-MugKGP/QuuaUH56h2hXrBL5+PzAaMigI6G5o9dIHhgPufHnIHLzbmSWSH0V1BGtI
-RSHExePHk/VrQkSO9Hft8iNdvJtEJ4eI4qYYwjYOpjkgri8N/daO6dmgY2S3NngH
-9eZsTo2dS8jt1HY9B7+jkVpoCYFaX3Eipet0MtnZPqCCi4EzGR+/79FIspJXPvWb
-ealEu91VFeqb9WGiPcSk4OZmKicrLx3Dw90Ts4VbR3AW5kxKWyOrFHTwSpZLs6+i
-4G3xrqZ85T5ZTvT4m7rZQDeoUq7k8WmBcUUlntWsmjBSvUKq2awTyI/+95rKeKwK
-cjHxUCXH1YKDcCkuqaS1NdSjrUXuhvKn8ESxpE/5QIqABr8AKvR3j//rXGqtqC7D
-rv7kMHviP0uJqzM15cYZ+BT6fwM04a2nF2wT/WPhk1DLIviYRQzZb5P2W/2nCOP4
-+bmB9PINM0yGc+OqHzelKGRKN/yh390eZiQygb/U43ceTAwXfVdIW0svb1+4dlQm
-mjPgQnTRSasOo4hFUK+IbeELB4gTswVpu02mdM4I0KlkK7mvYDxsZzY+OGxxb8Re
-k+MbwZ6DbMsfGt2VGGM9LWeaWrnPBhbR5XDhuNj4w/ca+GdiLdloRuD72uCGYed6
-UDP0ANRt6C8MGJqINmCOQceYgkhP8ColktTLk6b0DspmY9mTCBED5EXgD5o/qnlM
-ui9VFT75Rr9eELebT2s2IU+s69ESaTPrZ3bNDqSDMkeYbdzfcCsPwI9sz38fow==
+YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEhBV2NqUSBBMVJ3aGtZ
+Z3dVbmYvZUJudXhja1B1bUlHRGJzdi94N0FtSlNUenJvV3VadQpaOHR5bEpkYjJy
+UnI2OGoxWTZEN2FQaVRzU2tpd0g2TlBmRUhIcCtteDZBCi0+IHBpdi1wMjU2IHBE
+YXpSZyBBMVl3a25ZRUs4YU9seE5PQW1OWDZyOEh4RXRBZ0t1azZFSEt3T0lLcTQ3
+cAp1WFh4aFV0VG52VTFhM3VXUW41UG9XQnZ5bGUzajdqbGptUVRLdkdlemFnCi0+
+IDxVaW8nLWdyZWFzZSA8fSBAY0EuIDB+ClpEeFlvY1JSWFFoRFhsVGRXTXp6YjFF
+SXVlU0xwMzY0N05BCi0tLSBzNHFLbEZXRENpUkRqWTRLQ0N1QlZObFZtZFpmQkcr
+TWN1WFRobzZZN0lFCh1kjTRNXk8Xm3hqf5IjFjZ/ThsnLtLZ2U9wR+AQzVggENXI
+vkXAbCMAVH3Q+DUjCM0kwhp2+GJOW/U0KjEa/UGrwokZwzhs0M5yAjw4RiwyoOoR
+CxewEV36tvW/9ruIfQvqWxPNewknp4dmDo4YqJ5JM6R4EJgywHRqPDgMk+WZ6jXi
+ndYdmfo3K0i34DzmYMw8wIlc646V7UIIJYp0n8Ff0AiS78pzFvjlmtE3TdWqeeRX
+xNI3iQ6DRXirkiumoVItqU1ykWK3CbXEDQAHeKpGKNCJ/yT2v2Y27TZTJ3yGACNW
+dxedoJi1gh/kEUEL+adifIjbZiCFH+my8jVK7plWvav+0+G0cuK1euFNp/ZCPujA
+pFevpbwUkPWcNmbxFvAxd+8vO9e+2Msk6BRVNtOWvKoOQa2BXYDqM1qdOv2iV0Me
+V0VTDBRbNoyz/CrTyNEi3aYEFUvsHgnPD3XXB9uJFL0+wbLprVn2F0jVaBPublnl
+8XHKRL8aJS3q2u1CADXNdOMnYpoHHNFr77qBi2L4wIBWoqfWU5vNYUu8C49NwuxD
+dlIqw6yA/OcnQgFs+xKkOq+of9aRC65zHh2rxttsHo7RvjnQALnb3zLOOR56NhQ2
+ZQCkgrAQYGg6G0NtmK7H3N23yM12IqHmlBn8QRZCdb7hMMw/8gLf5RpreJviSqzo
+tOtZAxBC4UkZhAhQDBZ7GMzvHHwFQNd4ntXH6C7qiRJaIw+hlUI25yuGE/1k1s0o
+PHtEcXeuHqs2Sgdwe9nM9MdvZqpXGcsnuE7Z0xantXlOLWpx/t61IOPoPnhj0vOm
+q6ARC6jpFAUJ5v4UEf3Ss2bzbwfWFAekaRX1t4GVhhUHRK+OxO7xs3OsOya2sLzv
+kOCMjC6nsOlvkRE4xtMtM9Kdh2foCvPkxecChIVYkRWASDFmjAd+Sqo2rYTEOlF1
+zZttUMEFcLN0PQMfIAnLpn0LtaxwiodmdGtMEHWE3yMVQ98xYmfuoJuKrySDqfq0
+W5lPZjjx0mTUXZH5poRpg6JAr5I46Ag=
-----END AGE ENCRYPTED FILE-----
@@ -2,6 +2,7 @@
defaultBranch = main
[user]
{{- if eq .chezmoi.hostname "angmar" }}
+ # {{ .chezmoi.hostname }}
signingkey = ~/.ssh/yk-stationary.pub
{{- else }}
signingkey = ~/.ssh/yk-mobile.pub
@@ -49,5 +50,3 @@
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
required = true
-[url "git@git.sr.ht:"]
- insteadOf = https://git.sr.ht/
@@ -1,45 +1,47 @@
-----BEGIN AGE ENCRYPTED FILE-----
-YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEhBV2NqUSBBeXlITDNv
-RzFWZ1JiOVdKdXhleGFrbWU0ek9QaGVWdmptWDNTckJVTDNoTwpiUzcvSVpXYUg5
-OXJOdGVybnp4TXdzQTNVL1NnT3ZTSXBVektUOHdFbnBVCi0+IHBpdi1wMjU2IHBE
-YXpSZyBBc0o3TnpKajM2M1d4NEhBUGtYV2NHZlVUdDhZWDUzL05TR2p5c3JDWWMz
-LwpiOXBaWnV0a2Jmb0R2RSswSU1odHBmTUlTMlB2Q05oOHJ1dTQ1S0xUVTJZCi0t
-LSBYNGx0cnBJTmk2WGdTdERORVBoRDdxQ2RyT0VjZGVuck9KdGoyNU40OThvCutv
-MD+I/sNKpbSV4mNu8Q/rCRIrbYaibtdkaBk6uUo69dSChRzSaYnUbg9PB5VSw144
-nFRRydOKpiQC9PD/mL7UV9E0XIpgLEehlrYYKftWBUv7DuLFJgF74UOgzhy9xDAK
-OsGsAnU4itfuRRXGMnNv1reL6oGZLtxFb5uNCLuO6PoBjf2HrMMUQy2CccyUWEaA
-iLcnOpwELYRczHlFIgmu9ywOU83VV/h/XP0tcwHWkp+tCBMkBUBn2YccpH/y7FrI
-1pBb5oqGLGK0lBrEcaf49ylCTRHTKSXvHSWRdXjj/9ZLTayAUzXa4KZXEFf+YAFZ
-Jx9Fc5cDAp1nl9qOnwaqVLIdGHVtCIAdDZ9q/BaOMzmITfXzwWOF+m90dN1N2Dtm
-fWFWgun+RTZ0NzHM9vx5YhsatmPZ+zqOxTwwhbPcTdztvoeDk9O/U8vom3HlJcV3
-2H62LVkUmkIsyIdbNXOP9agy7tZNsJ/6tTvsgMqfbV0MiTChOTRWDMZ+AkR5r08v
-hF+ZvjlRJHaB7yYsQLQmXdSFE9R7eg3DekkLMdGfbxt53UZWe14QxrhEqRR+x1J3
-KupS1/+DNC9Gy2ISC9sSwK3/iNfkNCD8bRcOJX6+pZOJrX5rnGBa/ab3TCMw7waZ
-4WDefTgOl4bz5kwtfj2qLFhWvXjCY3xJI0AmF6/6qwmIdQtHDWp5gtHTtuuJaIuO
-oWoJLRHRULCVsaKvxyh3eO7yyBy/VBzCWBjpyc/ldxKzlsDPjqyJn3xRfd+vFrC8
-pn094vDoAa0LXHBr5z689NE1iNR6Q6X+6QXdZfA9r1L4OmZXZ7jX7w54UkcPVy0P
-9TPACvYZ3LCECHcPmCnivzZ0JrPlgsbxNLdo1tV1VwdyyllFQdOIoI7a/f8FOAYY
-ZdlGgLiw1iUqgPC4RwU5iRXIq0ezQLg22TFr3XUJx0JNp2mbhxCACHNKfHPJIENc
-TzDCPFfY5B4fRqh/nt5Jxz8O7M1GMstyJvG6rJlEO9/+AvL63bKAZdeM7rUlHcME
-q57vIatTKQfPopzgGFMZweIuZKHd++qfayPmGZ+T/ffxohqunFc5tQ4qhkG55TTd
-63/v7jUruPWS/E8TjMre4y0qi+lOKEGjEtdUjdOFlIhNw3JwJp0rKeZDC7zwQ6Mk
-z1TRnJPIqTwhJY3TIGmGVFVVT4iCCTLO3svFsZCJAbb30GsHudQwcYKDx1oUDi+A
-uDj8+199MoAVG7KmlbY8F5LtEoQPNXYmhUkwKWe4HBpM43nE2RDZ50mPLmNFJgoI
-9VPhprN75hRiOzPoCYHBnJlIpKWmoX6mx9lpg0GMhdIcs24vGTwy2DngW4IyEuuW
-Hp0RRvc7ZsZotAjz4dHmOo2O95lwPilmA5sgGj1ESEFzbDR9GibzKJzHD+vq4Jw3
-1ImoV3rASY1YfKXmGvpCPQt69HPMQlTErMEdmxGZIZ6577Bsva7oFQxt7Y0Kd9to
-M4N3S3ITPCxMtSYyY5n/80YtT/lcb1ltS2k7tNRAUaaDmQkbpqQlWPL7TjQZlCXz
-ti1IhtJavCG9ER69G3pKkgAY1gO2lyntnmHMooj0SbHza/5g8WTqL+rbQNyxOBok
-OX4PMvnT9E6/k2gpTkeRuCI3E1DWywKEB/RA0jHIZcU3WC05Qh2Yx8F3DLTW/hBn
-ooChNyagg8JgLBisK14TQy6qCL54DaEHM3ZPzo2bnibfXV3MABZ36hfm5j2q3g90
-UFvS4scOxMdVTob+DjFXQand88jR9ldmDZP9kXr2P/PEG96ghVmQ06HOy7e4CCrk
-xAMIjfGb4BjzbvpIODrBRW6JfK1YgSWZw3+zEZqYtxZvBQpZ4Q2Mif/nmpVVVovZ
-XmEgBVQIYWDzINbfDvdgTBquxRh43VclBZ7V6AbJsd5VWPMMLADHJj/s+ynsSsT1
-7i7tLJ2w0jlo3g6iFDs095z1qY+Ek0qCOc/pRIsQLG5sNs/gaT9NQ/hbIUV0hNlE
-Hb9yQeorEEGf9NwOmPLEtBQrKXqLteV2OpUQdGg22uyjv+adBNUQuVCG99cxBexO
-ucgvjdNtuahWYbzLOA6d6h3hKi0Nj9QRxJ88wp9bJFXsUGg8TCbGDsL8DMmtijL6
-ooRHl1qZN9TZhxFzKpx3nE7AAeyyiV5V0pRpMfNbNf9JMCVZTMcVW3yFK1pQCIY3
-QovAj/0gdb7KEJK8blub8EopvY8goSsFon0kxmmsssuml+vbypBkWlc+2eYqYZ6W
-Es7jCTwSmmdxIld1naR2Ti3115namC6SOBfqUPHrJcsSPtyWHYg8R8IOpioWnn5S
-h14l05vIg5zE8m3zl8Yzlp0ARJA1FHum+/l+Q1b8W9IG8Z9mgyjUjsJONVTzlB2X
+YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEhBV2NqUSBBdk5Za1JU
+VTJnUzE2Mk1QZW5ZdkZUU0QvVTFDTXRSM1pWNjNnWWlCY3ozMQo0a1lFa0xFVHBk
+MHp2QnByVUphalNCc0M2emtLSldHZUFwVFRFRGZ6dHpZCi0+IHBpdi1wMjU2IHBE
+YXpSZyBBeUNXcVlwTm56blFPc2hETy9SdnB4WHptcFFvSTlvc01rUmJGZ3dGQVZZ
+NAorVzRKcTZSdmtXR3kvRHBuSnlSUE8xcUsrR0lsKy9KV1ptNmZETUdVaUtVCi0+
+ID00Pi1ncmVhc2Ugay5fRj8nIElWN3dkRyA9TS1rVwpzYzQxKzkrdTZ2UXIrVDIw
+ZmdIbnU2Y1ZxaTdwUlIwZXRkYUw1bUJVdkovUkUyYwotLS0gWGZYd29qb3Q3SGFE
+WDJWNjNsb2Y1cXlZemsxMkhCcXQxc1JkaUNqcVdiSQohDWKEZ7K2JBAC8g9ekSlN
+DeNIbSnEGKEAfQpIi9sh23MuKbKM26zzK9KXqPm7uPwJ7RrstFiyybRYlLvBMgL/
+VOLV7pu3Poyt+UTpg2plmOFiaHSe96yZBauDzZDFTsuqJUysHyXzOyk6hC34k8zT
+luqBuZYlkQ0LJK/pF63nxU58ZaJAE6F3gWMjhdtwUKN7Uyt//wEfoZR/c2Dh9gYn
+hNc8EIIQxtdoCvLTobJ9uBY5AinDLLElbi9E+16HwitumhvC6DHatOJdFNFlCo3P
+hpexmj2iyRzx0v2WRo5rn4/IBljGoWL/8MZSz4g/SSfuBqb6uqy6lh99gSKD8Xnn
+4BX8Ne9lvMsHjHDCh5a9d6SZJR1G5XseK+S28DPtegZCG/AdoN36eNKyo13/6kFf
+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
-----END AGE ENCRYPTED FILE-----
@@ -1,58 +1,64 @@
-----BEGIN AGE ENCRYPTED FILE-----
-YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEhBV2NqUSBBdjVETGd1
-czA0TE1ISFdXRjRQY05uVVJTUVJhSzRSaHFqMWo0SUxwOUtTcwoyVFlvUGdkc2Ja
-YmRPcWtPb2JrRXRXRTVySThPaE9aSUpZOEMxTGVyNEdrCi0+IHBpdi1wMjU2IHBE
-YXpSZyBBc1pQQ1duek5RSHhZNTdxNWJVVTVMWTJSMGhpTGs3U3VUR04zR01MMWl4
-WApDa2o0aDlLYUQ3UTNiSlpqKzZPckJHUkkwYS9EcEw4a2hMTXZQTnNEVXpvCi0t
-LSBLRy9TbWdVd2ZyZnluSE8wRXFjaTE0TTdaeFJhRUIwRjMzR3RLRHRxNHdJCosk
-DjcVFTCpdzOmwL2vFZlBCplLt6YBVI8ELxMKydRCIhoM9aHbqjZ02ppIN2dYu1Fv
-vi3JYsrp9rSkesd+RSdIdxlLaDF6OKwcl+v/K7BisxUuNtdDDBIRB7ZCJxyDOd4z
-SEwh8PWKxu4mLOVULiY9CLEyzp3/hVPCQKcqFfswHjeNyx3LYf3ubGyioRmFhTKF
-s4+ccznvqiNrHlQrBxq6y2P/rhBjOVng2vq38odkSUi5sBZnlVQglEAoRSrokDrs
-T85voWFS44xQ+vG4VABVYJXLyNqsQ2PuH0U52ctcN6iJTkMBdz+YGvRagWKQTNCz
-P7kAj1xDRIejUtyKUD5Wps0R8j9mgbnLRvhUk8uox461EYJ/MVyF/26BOlZYXeSW
-w5U8dGgOscGl+DkHRPOHike+qkuer7JJRXp/ADurvRZhXJJ7AtLtE98vQpEwVGtv
-uthTMy6du1JWffl7UMxCQ7FLwgojMGLoFqN/1H74/DKuPTMESvV1D8XTUYoyxy4G
-vaC8ZXAAd8nshxLZweMRltiQj67wgEL3RYPHB/TL5DDtP2rRjiCZbdaHiYdVjJgH
-bzRPXlCkXPBgqW6Ehass/4I7lW/7aGwcMTYBNJaI8wDKnxPOiZ+40eV9Z35AVIIo
-MT7AMT6AaQ0zQTBZCOT9L1exzEwLMMsEmZ9GisUkHsOsqghSmQ57eRsW+deRPbHD
-PDCR/p2R/37tp0CLobnpyjiIR6ooJU+7nSI/T+vwInHUObqjjbMaNnWbQexgRv6z
-K3VQoznGIXNEnc1pQybTgDtQ61UH6jE6AlelO9/VVoK7dFAlHfyYD5FOpFcgAn2G
-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
+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
+dXpYSUJla3NId3hjQmtPTG5GcHE2dzU3aGNpY2RobW9IK0Q3cwo4bHNEd1loUkc3
+QUZ0ejd4bW9CLzFCRmpSY0Q5Tk5MN1lWS3NNVXB1TUY4Ci0+IHBpdi1wMjU2IHBE
+YXpSZyBBaG1wSE1rMEZtTEQ2WXFHMFNQL2JSZFhtelV5WHU4UWgzTGZyR3E4SEor
+SQpCU3pwUWVkRGs5SXZUbFU5eUM4cS9aSDhzV2JncUJsd25VY1dXZTNlR29rCi0+
+IG0tZ3JlYXNlICJcIGhBM1xfICpWLDM2R0JKICkKQTNWd2R6ODdLRFM1QmE0WEEw
+eUVYSDJTSi9oWVd4Umo0OERFbDRObkUzbHd4cGtxQkxsZVAzdFdEazBQbUlMOQo2
+dWUrcm1PcGl3Yy9HRGdybFI2SXBVc1QKLS0tIDNGM3I4VlNyR1J5MnhlenM5Y2I3
+WUNHSGZxOWZMcWtBUFhYZTJWUTJTUjAKuyf4O6+aRarG1AqEO2H+lVnAv1p5YXfj
+wL1ROgwqY/0pl0JONI/5bZKqx0odo/seDMpKENVBDZjU69riCVPRE4WJxRK77yk7
+zvBiR1A4i934JV231icsW8WzCvYs3n1e3kKWkF75ictXiV0rLYE27+HQJHwGf0ns
+rcyofuBVrkkhcscw77QYYJJkxvRuf7Xbcr24oacG7WIYgYvo+TDqqxxm6WmxVaib
++9YR/box73wM5H9Niof9tmjZE6RQEOSoUNs50wJL0hHxGNlK/7pm4KsrQdDcZGw6
+CjRsTyYxHwi3tlPltlyvsEQPQZRpsbLvCoDCioJl1lU8FvcozwMwVB0uJLTxJx41
+Q8I2RHL32y/Y45jevJURJlf1SKN5gIpljUZUPK6KN6Ta9Jvc+wl4DGbJOYiDqMzL
+9u/S483LyFWNrX/etAqlwr5riztuZAITOKUH4P/BYrGN8DA8sfBenDPuUVjlY1pd
+9N2+VA/4uBJjDirRqy0988lHUog480P9ZZsAq0E9J3wViWWNnO4yv0FceC8dFZN9
+2BkExlcLwx/JlqdrX1JwZVzeURsIlsCBmOV6p3Dga1+hwPnMDVnuo8lOg+HqpfqQ
+AIctVHdXsCyZ/91C/+pSQ3dLK6PW2FX9zIgs1z91+Mc6QpJX6jqao5NVZvNttB5v
+Y+VqO4aFTElMi7RC0gxzcVmuHq+2ZJQsiSzj6WTH1e9Zz6JJhbQ1iMPP21O14quq
+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
-----END AGE ENCRYPTED FILE-----
@@ -0,0 +1,27 @@
+-- HELLO, welcome to NormalNvim!
+-- ---------------------------------------
+-- This is the entry point of your config.
+-- ---------------------------------------
+
+-- LOAD SOURCE FILES BY ORDER:
+vim.loader.enable()
+for _, source in ipairs {
+ "base.1-options",
+ "base.2-lazy",
+ "base.3-autocmds",
+ "base.4-mappings",
+} do
+ local status_ok, error = pcall(require, source)
+ if not status_ok then vim.api.nvim_err_writeln("Failed to load " .. source .. "\n\n" .. error) end
+end
+
+-- ONCE ALL SOURCE FILES HAVE LOADED:
+-- Load the color scheme defined in ./lua/1-options.lua
+if base.default_colorscheme then
+ if not pcall(vim.cmd.colorscheme, base.default_colorscheme) then
+ require("base.utils").notify(
+ "Error setting up colorscheme: " .. base.default_colorscheme,
+ vim.log.levels.ERROR
+ )
+ end
+end
@@ -1,142 +0,0 @@
-let mapleader =","
-
-if ! filereadable(expand('~/.config/nvim/autoload/plug.vim'))
- echo "Downloading junegunn/vim-plug to manage plugins..."
- silent !mkdir -p ~/.config/nvim/autoload/
- silent !curl "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim" > ~/.config/nvim/autoload/plug.vim
-endif
-
-call plug#begin()
-Plug 'ap/vim-css-color' " highlight css colour codes with that color
-Plug 'tpope/vim-surround' " highlight open/close characters like [], {}, ()
-Plug 'wakatime/vim-wakatime' " Aggregate editor stats and metrics
-Plug 'catppuccin/vim', { 'as': 'catppuccin' }
-Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
-Plug 'github/copilot.vim'
-call plug#end()
-
-{{- if eq .theme_variant "dark"}}
-colorscheme catppuccin_macchiato
-{{- end }}
-{{- if eq .theme_variant "light"}}
-colorscheme catppuccin_latte
-{{- end }}
-
-" LaTeX config
-let g:livepreview_previewer = 'zathura'
-let g:livepreview_use_biber = 1
-
-" Grammorous config
-let g:grammarous#languagetool_cmd = 'java -cp ~/languagetool/languagetool-server.jar org.languagetool.server.HTTPServer --port 8081 --allow-origin "*"'
-syntax enable
-
-""
-" Some basics
-""
-" Make ctags for supported languages
-command! MakeTags !ctags -R .
-" Add all subdirs to working path so :find works well
-set path+=**
-" Status line completion menu
-set wildmenu
-" Set above menu to a vertical instead of horizontal list
-set wildmode=full,list,full
-" Wrap long lines that continue past the viewport
-set linebreak
-" Highlight the column the cursor is on
-set cursorcolumn
-" Highlight the line the cursor is on
-set cursorline
-" Enables more colors
-set termguicolors
-" If there are folds, close some of them on startup
-set foldlevelstart=99
-" Use system clipboard for all yanking/pasting
-set clipboard+=unnamedplus
-" Use tabs but display them as 4 spaces instead of 8
-set ts=4 sts=4 sw=4 expandtab
-" Round the indent to a multiple of sw
-set shiftround
-" Set hidden character characters
-set listchars=tab:▸\ ,eol:¬,nbsp:␣,trail:•,space:.,extends:→,precedes:←
-set backspace=indent,eol,start
-" Keep 12 lines above and below the cursor when scrolling
-set scrolloff=12
-" Disable mouse support
-set mouse=
-" Use indents to determine folds
-set foldmethod=indent
-" Set line numbers relative to current line
-set number nu
-" Show partial commands in the bottom right
-set showcmd
-" Show which mode you're in
-set showmode
-" Display partial matches when searching
-set incsearch
-" Highlight search results—hide with :noh
-set hlsearch
-" Wrap searches around the end of the file
-set wrapscan
-" Tell Vim to be more liberal with creating hidden buffers
-set hidden
-" Case-insensitive search unless term contains uppercase chars
-set smartcase
-
-" Statusbar theme
-let g:airline_powerline_fonts = 1
-let g:airline_theme='bubblegum'
-if !exists('g:airline_symbols')
- let g:airline_symbols = {}
-endif
-
-""
-" Keybindings
-""
-" Insert timestamp at the end of the line in this format: 20200527T113245
-nnoremap <C-t><C-s> m'A<C-R>=strftime('%Y%m%dT%H%M%S')<CR>
-" Open a new tab
-nnoremap <C-t>t :tabnew<CR>
-" Toggle hidden characters
-nnoremap <C-l> :set list!<CR>
-
-" Window management
-map <C-h> <C-w>h
-map <C-j> <C-w>j
-map <C-k> <C-w>k
-map <C-l> <C-w>l
-
-" only enable persistent undo if vim supports
-if has('persistent_undo')
- set undodir=$HOME/.config/nvim/undofile
- set undofile
-endif
-
-" Only enable autocommands when Vim supports them
-if has("autocmd")
- " Disables automatic commenting on newline:
- autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o
-
- ""
- " File-specific indentation settings
- ""
- autocmd FileType make setlocal ts=8 sts=8 sw=8 noexpandtab
- autocmd FileType yaml setlocal ts=2 sts=2 sw=2 expandtab
-
- ""
- " Markdown Configuration
- ""
- " Treat all .md files as markdown
- autocmd BufNewFile,BufRead *.md set filetype=markdown
- " Spellcheck in British English
- autocmd FileType markdown setlocal spell spelllang=en_gb
-
- ""
- " Working with LaTeX
- ""
- " Reduce udpatetime for faster previews
- autocmd BufNewFile,BufRead *.tex setfiletype tex
- autocmd FileType tex set ut=250
- autocmd FileType tex set colorcolumn=72
-
-endif
@@ -0,0 +1,93 @@
+-- HELLO, welcome to NormalNvim!
+-- ----------------------------------------
+-- Here you can define your nvim variables.
+-- ----------------------------------------
+
+-- NormalNvin lua globals
+_G.base = {}
+
+-- Theme
+base.default_colorscheme = "tokyonight-night"
+
+-- Options --------------------------------------------------------------------
+vim.opt.breakindent = true -- Wrap indent to match line start.
+vim.opt.clipboard = "unnamedplus" -- Connection to the system clipboard.
+vim.opt.cmdheight = 0 -- Hide command line unless needed.
+vim.opt.completeopt = { "menu", "menuone", "noselect" } -- Options for insert mode completion.
+vim.opt.copyindent = true -- Copy the previous indentation on autoindenting.
+vim.opt.cursorline = true -- Highlight the text line of the cursor.
+vim.opt.expandtab = true -- Enable the use of space in tab.
+vim.opt.fileencoding = "utf-8" -- File content encoding for the buffer.
+vim.opt.fillchars = { eob = " " } -- Disable `~` on nonexistent lines.
+vim.opt.foldenable = true -- Enable fold for nvim-ufo.
+vim.opt.foldlevel = 99 -- set highest foldlevel for nvim-ufo.
+vim.opt.foldlevelstart = 99 -- Start with all code unfolded.
+vim.opt.foldcolumn = "1" -- Show foldcolumn in nvim 0.9+.
+vim.opt.ignorecase = true -- Case insensitive searching.
+vim.opt.infercase = true -- Infer cases in keyword completion.
+
+vim.opt.laststatus = 3 -- Global statusline.
+vim.opt.linebreak = true -- Wrap lines at 'breakat'.
+vim.opt.number = true -- Show numberline.
+vim.opt.preserveindent = true -- Preserve indent structure as much as possible.
+vim.opt.pumheight = 10 -- Height of the pop up menu.
+vim.opt.relativenumber = false -- Show relative numberline.
+vim.opt.shiftwidth = 2 -- Number of space inserted for indentation.
+vim.opt.showmode = false -- Disable showing modes in command line.
+vim.opt.showtabline = 2 -- always display tabline.
+vim.opt.signcolumn = "yes" -- Always show the sign column.
+vim.opt.smartcase = true -- Case sensitivie searching.
+vim.opt.smartindent = false -- Smarter autoindentation.
+vim.opt.splitbelow = true -- Splitting a new window below the current one.
+vim.opt.splitright = true -- Splitting a new window at the right of the current one.
+vim.opt.tabstop = 2 -- Number of space in a tab.
+
+vim.opt.termguicolors = true -- Enable 24-bit RGB color in the TUI.
+vim.opt.timeoutlen = 500 -- Shorten key timeout length a little bit for which-key.
+vim.opt.undofile = true -- Enable persistent undo between session and reboots.
+vim.opt.updatetime = 300 -- Length of time to wait before triggering the plugin.
+vim.opt.virtualedit = "block" -- Allow going past end of line in visual block mode.
+vim.opt.writebackup = false -- Disable making a backup before overwriting a file.
+vim.opt.shada = "!,'1000,<50,s10,h" -- Remember the last 1000 opened files
+vim.opt.history = 1000 -- Number of commands to remember in a history table (per buffer).
+vim.opt.swapfile = false -- Ask what state to recover when opening a file that was not saved.
+vim.opt.wrap = true -- Disable wrapping of lines longer than the width of window.
+vim.opt.colorcolumn = "80" -- PEP8 like character limit vertical bar.
+vim.opt.mousescroll = "ver:1,hor:0" -- Disables hozirontal scroll in neovim.
+vim.opt.guicursor = "n:blinkon200,i-ci-ve:ver25" -- Enable cursor blink.
+vim.opt.autochdir = true -- Use current file dir as working dir (See project.nvim).
+vim.opt.scrolloff = 1000 -- Number of lines to leave before/after the cursor when scrolling. Setting a high value keep the cursor centered.
+vim.opt.sidescrolloff = 8 -- Same but for side scrolling.
+vim.opt.selection = "old" -- Don't select the newline symbol when using <End> on visual mode.
+
+vim.opt.viewoptions:remove "curdir" -- Disable saving current directory with views.
+vim.opt.shortmess:append { s = true, I = true } -- Disable startup message.
+vim.opt.backspace:append { "nostop" } -- Don't stop backspace at insert.
+vim.opt.diffopt:append { "algorithm:histogram", "linematch:60" } -- Enable linematch diff algorithm
+
+local is_android = vim.fn.isdirectory('/data') == 1
+if is_android then vim.opt.mouse = "v" else vim.opt.mouse = "a" end -- Enable scroll for android
+
+-- Globals --------------------------------------------------------------------
+vim.g.mapleader = " " -- Set leader key.
+vim.g.maplocalleader = "," -- Set default local leader key.
+vim.g.big_file = { size = 1024 * 100, lines = 10000 } -- For files bigger than this, disable 'treesitter' (+100kb).
+
+-- The next globals are toggleable with <space + l + u>
+vim.g.autoformat_enabled = false -- Enable auto formatting at start.
+vim.g.autopairs_enabled = false -- Enable autopairs at start.
+vim.g.cmp_enabled = true -- Enable completion at start.
+vim.g.codeactions_enabled = true -- Enable displaying 💡 where code actions can be used.
+vim.g.codelens_enabled = true -- Enable automatic codelens refreshing for lsp that support it.
+vim.g.diagnostics_mode = 3 -- Set code linting (0=off, 1=only show in status line, 2=virtual text off, 3=all on).
+vim.g.icons_enabled = true -- Enable icons in the UI (disable if no nerd font is available).
+vim.g.inlay_hints_enabled = false -- Enable always show function parameter names.
+vim.g.lsp_round_borders_enabled = true -- Enable round borders for lsp hover and signatureHelp.
+vim.g.lsp_signature_enabled = true -- Enable automatically showing lsp help as you write function parameters.
+vim.g.notifications_enabled = true -- Enable notifications.
+vim.g.semantic_tokens_enabled = true -- Enable lsp semantic tokens at start.
+vim.g.url_effect_enabled = true -- Highlight URLs with an underline effect.
+
+
+
+
@@ -0,0 +1,75 @@
+-- Lazy.nvim config file.
+
+-- DESCRIPTION:
+-- Use this file to configure the way you get updates.
+
+-- Sections:
+-- -> lazy updater options → choose your lazy updates channel here.
+-- -> extra behaviors → extra stuff we add to lazy for better UX.
+-- -> assign spec → if channel==stable, uses lazy_snatshot.lua
+-- -> setup using spec → actual setup.
+
+
+-- lazy updater options
+-- Use the same values you have in the plugin `distroupdate.nvim`
+local updater = {
+ channel = "stable", -- 'nightly', or 'stable'
+ snapshot_module = "lazy_snapshot" -- snapshot file name without extension.
+}
+
+-- lazyload extra behavior
+-- * If plugins need to be installed → auto launch lazy at startup.
+-- * When lazy finishes installing plugins → check for mason updates too.
+-- (but not when updating them)
+-- * Then show notifications and stuff.
+local lazypath = vim.fn.stdpath "data" .. "/lazy/lazy.nvim"
+if not vim.uv.fs_stat(lazypath) then
+ local output = vim.fn.system {
+ "git",
+ "clone",
+ "--filter=blob:none",
+ "--branch=stable",
+ "https://github.com/folke/lazy.nvim.git",
+ lazypath,
+ }
+ if vim.api.nvim_get_vvar "shell_error" ~= 0 then
+ vim.api.nvim_err_writeln("Error cloning lazy.nvim repository...\n\n" .. output)
+ end
+ local oldcmdheight = vim.opt.cmdheight:get()
+ vim.opt.cmdheight = 1
+ vim.notify "Please wait while plugins are installed..."
+ vim.api.nvim_create_autocmd("User", {
+ desc = "Load Mason and Treesitter after Lazy installs plugins",
+ once = true,
+ pattern = "LazyInstall",
+ callback = function()
+ vim.cmd.bw()
+ vim.opt.cmdheight = oldcmdheight
+ vim.tbl_map(function(module) pcall(require, module) end, { "nvim-treesitter", "mason" })
+ -- Note: This event will also trigger a Mason update in distroupdate.nvim
+ end,
+ })
+end
+vim.opt.rtp:prepend(lazypath)
+
+-- assign spec (if pin_plugins is true, load ./lua/lazy_snapshot.lua).
+local pin_plugins = updater.channel == "stable"
+local spec = pin_plugins and { { import = updater.snapshot_module } } or {}
+vim.list_extend(spec, { { import = "plugins" } })
+
+-- Require lazy and pass the spec.
+require("lazy").setup({
+ spec = spec,
+ defaults = { lazy = true },
+ performance = {
+ rtp = { -- Use deflate to download faster from the plugin repos.
+ disabled_plugins = {
+ "tohtml", "gzip", "zipPlugin", "netrwPlugin", "tarPlugin"
+ },
+ },
+ },
+ -- Enable luarocks if installed.
+ rocks = { enabled = vim.fn.executable("luarocks") == 1 },
+ -- We don't use this, so create it in a disposable place.
+ lockfile = vim.fn.stdpath("cache") .. "/lazy-lock.json",
+})
@@ -0,0 +1,281 @@
+-- General usage autocmds.
+
+-- DESCRIPTION:
+-- All autocmds are defined here.
+
+-- Sections:
+-- ## EXTRA LOGIC
+-- -> 1. Events to load plugins faster.
+-- -> 2. Save/restore window layout when possible.
+-- -> 3. Launch alpha greeter on startup.
+-- -> 4. Update neotree when closing the git client.
+-- -> 5. Create parent directories when saving a file.
+--
+-- ## COOL HACKS
+-- -> 6. Effect: URL underline.
+-- -> 7. Customize right click contextual menu.
+-- -> 8. Unlist quickfix buffers if the filetype changes.
+-- -> 9. Close all notifications on BufWritePre.
+--
+-- ## COMMANDS
+-- -> 10. Neotest commands.
+-- -> Extra commands.
+
+local autocmd = vim.api.nvim_create_autocmd
+local cmd = vim.api.nvim_create_user_command
+local utils = require("base.utils")
+local is_available = utils.is_available
+
+-- ## EXTRA LOGIC -----------------------------------------------------------
+-- 1. Events to load plugins faster → 'BaseFile'/'BaseGitFile'/'BaseDefered':
+-- this is pretty much the same thing as the event 'BufEnter',
+-- but without increasing the startup time displayed in the greeter.
+autocmd({ "BufReadPost", "BufNewFile", "BufWritePost" }, {
+ desc = "Nvim user events for file detection (BaseFile and BaseGitFile)",
+ callback = function(args)
+ local empty_buffer = vim.fn.resolve(vim.fn.expand "%") == ""
+ local greeter = vim.api.nvim_get_option_value("filetype", { buf = args.buf }) == "alpha"
+ local git_repo = utils.run_cmd(
+ { "git", "-C", vim.fn.fnamemodify(vim.fn.resolve(vim.fn.expand "%"), ":p:h"), "rev-parse" }, false)
+
+ -- For any file exept empty buffer, or the greeter (alpha)
+ if not (empty_buffer or greeter) then
+ utils.trigger_event("User BaseFile")
+
+ -- Is the buffer part of a git repo?
+ if git_repo then
+ utils.trigger_event("User BaseGitFile")
+ end
+ end
+ end,
+})
+autocmd({ "VimEnter" }, {
+ desc = "Nvim user event that trigger a few ms after nvim starts",
+ callback = function()
+ -- If nvim is opened passing a filename, trigger the event inmediatelly.
+ if #vim.fn.argv() >= 1 then
+ -- In order to avoid visual glitches.
+ utils.trigger_event("User BaseDefered", true)
+ utils.trigger_event("BufEnter", true) -- also, initialize tabline_buffers.
+ else -- Wait some ms before triggering the event.
+ vim.defer_fn(function()
+ utils.trigger_event("User BaseDefered")
+ end, 70)
+ end
+ end,
+})
+
+-- 2. Save/restore window layout when possible.
+autocmd({ "BufWinLeave", "BufWritePost", "WinLeave" }, {
+ desc = "Save view with mkview for real files",
+ callback = function(args)
+ if vim.b[args.buf].view_activated then
+ vim.cmd.mkview { mods = { emsg_silent = true } }
+ end
+ end,
+})
+autocmd("BufWinEnter", {
+ desc = "Try to load file view if available and enable view saving for real files",
+ callback = function(args)
+ if not vim.b[args.buf].view_activated then
+ local filetype =
+ vim.api.nvim_get_option_value("filetype", { buf = args.buf })
+ local buftype =
+ vim.api.nvim_get_option_value("buftype", { buf = args.buf })
+ local ignore_filetypes = { "gitcommit", "gitrebase", "svg", "hgcommit" }
+ if
+ buftype == ""
+ and filetype
+ and filetype ~= ""
+ and not vim.tbl_contains(ignore_filetypes, filetype)
+ then
+ vim.b[args.buf].view_activated = true
+ vim.cmd.loadview { mods = { emsg_silent = true } }
+ end
+ end
+ end,
+})
+
+-- 3. Launch alpha greeter on startup
+if is_available "alpha-nvim" then
+ autocmd({ "User", "BufEnter" }, {
+ desc = "Disable status and tablines for alpha",
+ callback = function(args)
+ local is_filetype_alpha = vim.api.nvim_get_option_value(
+ "filetype", { buf = 0 }) == "alpha"
+ local is_empty_file = vim.api.nvim_get_option_value(
+ "buftype", { buf = 0 }) == "nofile"
+ if ((args.event == "User" and args.file == "AlphaReady") or
+ (args.event == "BufEnter" and is_filetype_alpha)) and
+ not vim.g.before_alpha
+ then
+ vim.g.before_alpha = {
+ showtabline = vim.opt.showtabline:get(),
+ laststatus = vim.opt.laststatus:get()
+ }
+ vim.opt.showtabline, vim.opt.laststatus = 0, 0
+ elseif
+ vim.g.before_alpha
+ and args.event == "BufEnter"
+ and not is_empty_file
+ then
+ vim.opt.laststatus = vim.g.before_alpha.laststatus
+ vim.opt.showtabline = vim.g.before_alpha.showtabline
+ vim.g.before_alpha = nil
+ end
+ end,
+ })
+ autocmd("VimEnter", {
+ desc = "Start Alpha only when nvim is opened with no arguments",
+ callback = function()
+ -- Precalculate conditions.
+ local lines = vim.api.nvim_buf_get_lines(0, 0, 2, false)
+ local buf_not_empty = vim.fn.argc() > 0
+ or #lines > 1
+ or (#lines == 1 and lines[1]:len() > 0)
+ local buflist_not_empty = #vim.tbl_filter(
+ function(bufnr) return vim.bo[bufnr].buflisted end,
+ vim.api.nvim_list_bufs()
+ ) > 1
+ local buf_not_modifiable = not vim.o.modifiable
+
+ -- Return instead of opening alpha if any of these conditions occur.
+ if buf_not_modifiable or buf_not_empty or buflist_not_empty then
+ return
+ end
+ for _, arg in pairs(vim.v.argv) do
+ if arg == "-b"
+ or arg == "-c"
+ or vim.startswith(arg, "+")
+ or arg == "-S"
+ then
+ return
+ end
+ end
+
+ -- All good? Show alpha.
+ require("alpha").start(true, require("alpha").default_config)
+ vim.schedule(function() vim.cmd.doautocmd "FileType" end)
+ end,
+ })
+end
+
+-- 4. Update neotree when closin the git client.
+if is_available "neo-tree.nvim" then
+ autocmd("TermClose", {
+ pattern = { "*lazygit", "*gitui" },
+ desc = "Refresh Neo-Tree git when closing lazygit/gitui",
+ callback = function()
+ local manager_avail, manager = pcall(require, "neo-tree.sources.manager")
+ if manager_avail then
+ for _, source in ipairs {
+ "filesystem",
+ "git_status",
+ "document_symbols",
+ } do
+ local module = "neo-tree.sources." .. source
+ if package.loaded[module] then
+ manager.refresh(require(module).name)
+ end
+ end
+ end
+ end,
+ })
+end
+
+-- 5. Create parent directories when saving a file.
+autocmd("BufWritePre", {
+ desc = "Automatically create parent directories if they don't exist when saving a file",
+ callback = function(args)
+ local buf_is_valid_and_listed = vim.api.nvim_buf_is_valid(args.buf)
+ and vim.bo[args.buf].buflisted
+
+ if buf_is_valid_and_listed then
+ vim.fn.mkdir(vim.fn.fnamemodify(
+ vim.loop.fs_realpath(args.match) or args.match, ":p:h"), "p")
+ end
+ end,
+})
+
+-- ## COOL HACKS ------------------------------------------------------------
+-- 6. Effect: URL underline.
+vim.api.nvim_set_hl(0, 'HighlightURL', { underline = true })
+autocmd({ "VimEnter", "FileType", "BufEnter", "WinEnter" }, {
+ desc = "URL Highlighting",
+ callback = function() utils.set_url_effect() end,
+})
+
+-- 7. Customize right click contextual menu.
+autocmd("VimEnter", {
+ desc = "Disable right contextual menu warning message",
+ callback = function()
+ -- Disable right click message
+ vim.api.nvim_command [[aunmenu PopUp.How-to\ disable\ mouse]]
+ -- vim.api.nvim_command [[aunmenu PopUp.-1-]] -- You can remode a separator like this.
+ vim.api.nvim_command [[menu PopUp.Toggle\ \Breakpoint <cmd>:lua require('dap').toggle_breakpoint()<CR>]]
+ vim.api.nvim_command [[menu PopUp.-2- <Nop>]]
+ vim.api.nvim_command [[menu PopUp.Start\ \Compiler <cmd>:CompilerOpen<CR>]]
+ vim.api.nvim_command [[menu PopUp.Start\ \Debugger <cmd>:DapContinue<CR>]]
+ vim.api.nvim_command [[menu PopUp.Run\ \Test <cmd>:Neotest run<CR>]]
+ end,
+})
+
+-- 8. Unlist quickfix buffers if the filetype changes.
+autocmd("FileType", {
+ desc = "Unlist quickfist buffers",
+ pattern = "qf",
+ callback = function() vim.opt_local.buflisted = false end,
+})
+
+-- 9. Close all notifications on BufWritePre.
+autocmd("BufWritePre", {
+ desc = "Close all notifications on BufWritePre",
+ callback = function()
+ require("notify").dismiss({ pending = true, silent = true })
+ end,
+})
+
+-- ## COMMANDS --------------------------------------------------------------
+
+-- 10. Testing commands
+-- Aditional commands to the ones implemented in neotest.
+-------------------------------------------------------------------
+
+-- Customize this command to work as you like
+cmd("TestNodejs", function()
+ vim.cmd ":ProjectRoot" -- cd the project root (requires project.nvim)
+ vim.cmd ":TermExec cmd='npm run test'" -- convention to run tests on nodejs
+ -- You can generate code coverage by add this to your project's packages.json
+ -- "tests": "jest --coverage"
+end, { desc = "Run all unit tests for the current nodejs project" })
+
+-- Customize this command to work as you like
+cmd("TestNodejsE2e", function()
+ vim.cmd ":ProjectRoot" -- cd the project root (requires project.nvim)
+ vim.cmd ":TermExec cmd='npm run e2e'" -- Conventional way to call e2e in nodejs (requires ToggleTerm)
+end, { desc = "Run e2e tests for the current nodejs project" })
+
+-- Extra commands
+----------------------------------------------
+
+-- Change working directory
+cmd("Cwd", function()
+ vim.cmd ":cd %:p:h"
+ vim.cmd ":pwd"
+end, { desc = "cd current file's directory" })
+
+-- Set working directory (alias)
+cmd("Swd", function()
+ vim.cmd ":cd %:p:h"
+ vim.cmd ":pwd"
+end, { desc = "cd current file's directory" })
+
+-- Write all buffers
+cmd("WriteAllBuffers", function()
+ vim.cmd "wa"
+end, { desc = "Write all changed buffers" })
+
+-- Close all notifications
+cmd("CloseNotifications", function()
+ require("notify").dismiss({ pending = true, silent = true })
+end, { desc = "Dismiss all notifications" })
@@ -0,0 +1,1616 @@
+-- Keybindings (qwerty).
+
+-- DESCRIPTION:
+-- All mappings are defined here.
+
+-- Sections:
+-- ## Base bindings
+-- -> icons displayed on which-key.nvim
+-- -> standard operations
+-- -> clipboard
+-- -> search highlighting
+-- -> improved tabulation
+-- -> improved gg
+-- -> packages
+-- -> buffers/tabs [buffers]
+-- -> ui toggles [ui]
+-- -> shifted movement keys
+-- -> cmdline autocompletion
+-- -> special cases
+
+-- ## Plugin bindings
+-- -> alpha-nvim
+-- -> git [git]
+-- -> file browsers
+-- -> session manager
+-- -> smart-splits.nvim
+-- -> aerial.nvim
+-- -> litee-calltree.nvim
+-- -> telescope.nivm [find]
+-- -> toggleterm.nvim
+-- -> dap.nvim [debugger]
+-- -> tests [tests]
+-- -> nvim-ufo
+-- -> code documentation [docs]
+-- -> ask chatgpt [neural]
+-- -> hop.nvim
+-- -> mason-lspconfig.nvim [lsp]
+
+--
+-- KEYBINDINGS REFERENCE
+-- -------------------------------------------------------------------
+-- | Mode | Norm | Ins | Cmd | Vis | Sel | Opr | Term | Lang |
+-- Command +------+-----+-----+-----+-----+-----+------+------+
+-- [nore]map | yes | - | - | yes | yes | yes | - | - |
+-- n[nore]map | yes | - | - | - | - | - | - | - |
+-- [nore]map! | - | yes | yes | - | - | - | - | - |
+-- i[nore]map | - | yes | - | - | - | - | - | - |
+-- c[nore]map | - | - | yes | - | - | - | - | - |
+-- v[nore]map | - | - | - | yes | yes | - | - | - |
+-- x[nore]map | - | - | - | yes | - | - | - | - |
+-- s[nore]map | - | - | - | - | yes | - | - | - |
+-- o[nore]map | - | - | - | - | - | yes | - | - |
+-- t[nore]map | - | - | - | - | - | - | yes | - |
+-- l[nore]map | - | yes | yes | - | - | - | - | yes |
+-- -------------------------------------------------------------------
+
+local M = {}
+local utils = require "base.utils"
+local get_icon = utils.get_icon
+local is_available = utils.is_available
+local ui = require "base.utils.ui"
+local maps = require("base.utils").get_mappings_template()
+local is_android = vim.fn.isdirectory('/data') == 1 -- true if on android
+
+-- -------------------------------------------------------------------------
+--
+-- ## Base bindings ########################################################
+--
+-- -------------------------------------------------------------------------
+
+-- icons displayed on which-key.nvim ---------------------------------------
+local icons = {
+ f = { desc = get_icon("Search", 1, true) .. "Find" },
+ p = { desc = get_icon("Package", 1, true) .. "Packages" },
+ l = { desc = get_icon("ActiveLSP", 1, true) .. "LSP" },
+ u = { desc = get_icon("Window", 1, true) .. "UI" },
+ b = { desc = get_icon("Tab", 1, true) .. "Buffers" },
+ bs = { desc = get_icon("Sort", 1, true) .. "Sort Buffers" },
+ c = { desc = get_icon("Run", 1, true) .. "Compiler" },
+ d = { desc = get_icon("Debugger", 1, true) .. "Debugger" },
+ tt = { desc = get_icon("Test", 1, true) .. "Test" },
+ dc = { desc = get_icon("Docs", 1, true) .. "Docs" },
+ g = { desc = get_icon("Git", 1, true) .. "Git" },
+ S = { desc = get_icon("Session", 1, true) .. "Session" },
+ t = { desc = get_icon("Terminal", 1, true) .. "Terminal" },
+}
+
+-- standard Operations -----------------------------------------------------
+maps.n["j"] =
+{ "v:count == 0 ? 'gj' : 'j'", expr = true, desc = "Move cursor down" }
+maps.n["k"] =
+{ "v:count == 0 ? 'gk' : 'k'", expr = true, desc = "Move cursor up" }
+maps.n["<leader>w"] = { "<cmd>w<cr>", desc = "Save" }
+maps.n["<leader>W"] =
+{ function() vim.cmd "SudaWrite" end, desc = "Save as sudo" }
+maps.n["<leader>n"] = { "<cmd>enew<cr>", desc = "New file" }
+maps.n["<Leader>/"] = { "gcc", remap = true, desc = "Toggle comment line" }
+maps.x["<Leader>/"] = { "gc", remap = true, desc = "Toggle comment" }
+maps.n["gx"] =
+{ utils.open_with_program, desc = "Open the file under cursor with a program" }
+maps.n["<C-s>"] = { "<cmd>w!<cr>", desc = "Force write" }
+maps.n["|"] = { "<cmd>vsplit<cr>", desc = "Vertical Split" }
+maps.n["\\"] = { "<cmd>split<cr>", desc = "Horizontal Split" }
+maps.i["<C-BS>"] = { "<C-W>", desc = "Enable CTRL+backsace to delete." }
+maps.n["0"] =
+{ "^", desc = "Go to the fist character of the line (aliases 0 to ^)" }
+maps.n["<leader>q"] = { "<cmd>confirm q<cr>", desc = "Quit" }
+maps.n["<leader>q"] = {
+ function()
+ -- Ask user for confirmation
+ local choice = vim.fn.confirm("Do you really want to exit nvim?", "&Yes\n&No", 2)
+ if choice == 1 then
+ -- If user confirms, but there are still files to be saved: Ask
+ vim.cmd('confirm quit')
+ end
+ end,
+ desc = "Quit",
+}
+maps.n["<Tab>"] = {
+ "<Tab>",
+ noremap = true,
+ silent = true,
+ expr = false,
+ desc = "FIX: Prevent TAB from behaving like <C-i>, as they share the same internal code",
+}
+
+-- clipboard ---------------------------------------------------------------
+
+-- BUG: We disable these mappings on termux by default because <C-y>
+-- is the keycode for scrolling, and remapping it would break it.
+if not is_android then
+ -- only useful when the option clipboard is commented on ./1-options.lua
+ maps.n["<C-y>"] = { '"+y<esc>', desc = "Copy to cliboard" }
+ maps.x["<C-y>"] = { '"+y<esc>', desc = "Copy to cliboard" }
+ maps.n["<C-d>"] = { '"+y<esc>dd', desc = "Copy to clipboard and delete line" }
+ maps.x["<C-d>"] = { '"+y<esc>dd', desc = "Copy to clipboard and delete line" }
+ maps.n["<C-p>"] = { '"+p<esc>', desc = "Paste from clipboard" }
+end
+
+-- Make 'c' key not copy to clipboard when changing a character.
+maps.n["c"] = { '"_c', desc = "Change without yanking" }
+maps.n["C"] = { '"_C', desc = "Change without yanking" }
+maps.x["c"] = { '"_c', desc = "Change without yanking" }
+maps.x["C"] = { '"_C', desc = "Change without yanking" }
+
+-- Make 'x' key not copy to clipboard when deleting a character.
+maps.n["x"] = {
+ -- Also let's allow 'x' key to delete blank lines in normal mode.
+ function()
+ if vim.fn.col "." == 1 then
+ local line = vim.fn.getline "."
+ if line:match "^%s*$" then
+ vim.api.nvim_feedkeys('"_dd', "n", false)
+ vim.api.nvim_feedkeys("$", "n", false)
+ else
+ vim.api.nvim_feedkeys('"_x', "n", false)
+ end
+ else
+ vim.api.nvim_feedkeys('"_x', "n", false)
+ end
+ end,
+ desc = "Delete character without yanking it",
+}
+maps.x["x"] = { '"_x', desc = "Delete all characters in line" }
+
+-- Same for shifted X
+maps.n["X"] = {
+ -- Also let's allow 'x' key to delete blank lines in normal mode.
+ function()
+ if vim.fn.col "." == 1 then
+ local line = vim.fn.getline "."
+ if line:match "^%s*$" then
+ vim.api.nvim_feedkeys('"_dd', "n", false)
+ vim.api.nvim_feedkeys("$", "n", false)
+ else
+ vim.api.nvim_feedkeys('"_X', "n", false)
+ end
+ else
+ vim.api.nvim_feedkeys('"_X', "n", false)
+ end
+ end,
+ desc = "Delete before character without yanking it",
+}
+maps.x["X"] = { '"_X', desc = "Delete all characters in line" }
+
+-- Override nvim default behavior so it doesn't auto-yank when pasting on visual mode.
+maps.x["p"] = { "P", desc = "Paste content you've previourly yanked" }
+maps.x["P"] = { "p", desc = "Yank what you are going to override, then paste" }
+
+-- search highlighting ------------------------------------------------------
+-- use ESC to clear hlsearch, while preserving its original functionality.
+--
+-- TIP: If you prefer, use <leader>ENTER instead of <ESC>
+-- to avoid triggering it by accident.
+maps.n["<ESC>"] = {
+ function()
+ if vim.fn.hlexists "Search" then
+ vim.cmd "nohlsearch"
+ else
+ vim.api.nvim_feedkeys(
+ vim.api.nvim_replace_termcodes("<ESC>", true, true, true),
+ "n",
+ true
+ )
+ end
+ end,
+}
+
+-- Improved tabulation ------------------------------------------------------
+maps.x["<S-Tab>"] = { "<gv", desc = "unindent line" }
+maps.x["<Tab>"] = { ">gv", desc = "indent line" }
+maps.x["<"] = { "<gv", desc = "unindent line" }
+maps.x[">"] = { ">gv", desc = "indent line" }
+
+-- improved gg --------------------------------------------------------------
+maps.n["gg"] = {
+ function()
+ vim.g.minianimate_disable = true
+ if vim.v.count > 0 then
+ vim.cmd("normal! " .. vim.v.count .. "gg")
+ else
+ vim.cmd "normal! gg0"
+ end
+ vim.g.minianimate_disable = false
+ end,
+ desc = "gg and go to the first position",
+}
+maps.n["G"] = {
+ function()
+ vim.g.minianimate_disable = true
+ vim.cmd "normal! G$"
+ vim.g.minianimate_disable = false
+ end,
+ desc = "G and go to the last position",
+}
+maps.x["gg"] = {
+ function()
+ vim.g.minianimate_disable = true
+ if vim.v.count > 0 then
+ vim.cmd("normal! " .. vim.v.count .. "gg")
+ else
+ vim.cmd "normal! gg0"
+ end
+ vim.g.minianimate_disable = false
+ end,
+ desc = "gg and go to the first position (visual)",
+}
+maps.x["G"] = {
+ function()
+ vim.g.minianimate_disable = true
+ vim.cmd "normal! G$"
+ vim.g.minianimate_disable = false
+ end,
+ desc = "G and go to the last position (visual)",
+}
+maps.n["<C-a>"] = { -- to move to the previous position press ctrl + oo
+ function()
+ vim.g.minianimate_disable = true
+ vim.cmd "normal! gg0vG$"
+ vim.g.minianimate_disable = false
+ end,
+ desc = "Visually select all",
+}
+
+-- packages -----------------------------------------------------------------
+-- lazy
+maps.n["<leader>p"] = icons.p
+maps.n["<leader>pu"] =
+{ function() require("lazy").check() end, desc = "Lazy open" }
+maps.n["<leader>pU"] =
+{ function() require("lazy").update() end, desc = "Lazy update" }
+
+-- mason
+if is_available "mason.nvim" then
+ maps.n["<leader>pm"] = { "<cmd>Mason<cr>", desc = "Mason open" }
+ maps.n["<leader>pM"] = { "<cmd>MasonUpdateAll<cr>", desc = "Mason update" }
+end
+
+-- treesitter
+if is_available "nvim-treesitter" then
+ maps.n["<leader>pT"] = { "<cmd>TSUpdate<cr>", desc = "Treesitter update" }
+ maps.n["<leader>pt"] = { "<cmd>TSInstallInfo<cr>", desc = "Treesitter open" }
+end
+
+-- nvim updater
+maps.n["<leader>pD"] = { "<cmd>DistroUpdate<cr>", desc = "Distro update" }
+maps.n["<leader>pv"] = { "<cmd>DistroReadVersion<cr>", desc = "Distro version" }
+maps.n["<leader>pc"] = { "<cmd>DistroReadChangelog<cr>", desc = "Distro changelog" }
+
+-- buffers/tabs [buffers ]--------------------------------------------------
+maps.n["<leader>c"] = { -- Close window and buffer at the same time.
+ function() require("heirline-components.buffer").wipe() end,
+ desc = "Wipe buffer",
+}
+maps.n["<leader>C"] = { -- Close buffer keeping the window.
+ function() require("heirline-components.buffer").close() end,
+ desc = "Close buffer",
+}
+-- Close buffer keeping the window → Without confirmation.
+-- maps.n["<leader>X"] = {
+-- function() require("heirline-components.buffer").close(0, true) end,
+-- desc = "Force close buffer",
+--
+maps.n["<leader>ba"] = {
+ function() vim.cmd "wa" end,
+ desc = "Write all changed buffers",
+}
+maps.n["]b"] = {
+ function()
+ require("heirline-components.buffer").nav(vim.v.count > 0 and vim.v.count or 1)
+ end,
+ desc = "Next buffer",
+}
+maps.n["[b"] = {
+ function()
+ require("heirline-components.buffer").nav(-(vim.v.count > 0 and vim.v.count or 1))
+ end,
+ desc = "Previous buffer",
+}
+maps.n[">b"] = {
+ function()
+ require("heirline-components.buffer").move(vim.v.count > 0 and vim.v.count or 1)
+ end,
+ desc = "Move buffer tab right",
+}
+maps.n["<b"] = {
+ function()
+ require("heirline-components.buffer").move(-(vim.v.count > 0 and vim.v.count or 1))
+ end,
+ desc = "Move buffer tab left",
+}
+
+maps.n["<leader>b"] = icons.b
+maps.n["<leader>bc"] = {
+ function() require("heirline-components.buffer").close_all(true) end,
+ desc = "Close all buffers except current",
+}
+maps.n["<leader>bC"] = {
+ function() require("heirline-components.buffer").close_all() end,
+ desc = "Close all buffers",
+}
+maps.n["<leader>bb"] = {
+ function()
+ require("heirline-components.all").heirline.buffer_picker(
+ function(bufnr) vim.api.nvim_win_set_buf(0, bufnr) end
+ )
+ end,
+ desc = "Select buffer from tabline",
+}
+maps.n["<leader>bd"] = {
+ function()
+ require("heirline-components.all").heirline.buffer_picker(
+ function(bufnr) require("heirline-components.buffer").close(bufnr) end
+ )
+ end,
+ desc = "Delete buffer from tabline",
+}
+maps.n["<leader>bl"] = {
+ function() require("heirline-components.buffer").close_left() end,
+ desc = "Close all buffers to the left",
+}
+maps.n["<leader>br"] = {
+ function() require("heirline-components.buffer").close_right() end,
+ desc = "Close all buffers to the right",
+}
+maps.n["<leader>bs"] = icons.bs
+maps.n["<leader>bse"] = {
+ function() require("heirline-components.buffer").sort "extension" end,
+ desc = "Sort by extension (buffers)",
+}
+maps.n["<leader>bsr"] = {
+ function() require("heirline-components.buffer").sort "unique_path" end,
+ desc = "Sort by relative path (buffers)",
+}
+maps.n["<leader>bsp"] = {
+ function() require("heirline-components.buffer").sort "full_path" end,
+ desc = "Sort by full path (buffers)",
+}
+maps.n["<leader>bsi"] = {
+ function() require("heirline-components.buffer").sort "bufnr" end,
+ desc = "Sort by buffer number (buffers)",
+}
+maps.n["<leader>bsm"] = {
+ function() require("heirline-components.buffer").sort "modified" end,
+ desc = "Sort by modification (buffers)",
+}
+maps.n["<leader>b\\"] = {
+ function()
+ require("heirline-components.all").heirline.buffer_picker(function(bufnr)
+ vim.cmd.split()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ end)
+ end,
+ desc = "Horizontal split buffer from tabline",
+}
+maps.n["<leader>b|"] = {
+ function()
+ require("heirline-components.all").heirline.buffer_picker(function(bufnr)
+ vim.cmd.vsplit()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ end)
+ end,
+ desc = "Vertical split buffer from tabline",
+}
+
+-- quick movement aliases
+maps.n["<C-k>"] = {
+ function()
+ require("heirline-components.buffer").nav(vim.v.count > 0 and vim.v.count or 1)
+ end,
+ desc = "Next buffer",
+}
+maps.n["<C-j>"] = {
+ function()
+ require("heirline-components.buffer").nav(-(vim.v.count > 0 and vim.v.count or 1))
+ end,
+ desc = "Previous buffer",
+}
+maps.n["<S-Down>"] = {
+ function() vim.api.nvim_feedkeys("5j", "n", true) end,
+ desc = "Fast move down",
+}
+maps.n["<S-Up>"] = {
+ function() vim.api.nvim_feedkeys("5k", "n", true) end,
+ desc = "Fast move up",
+}
+
+-- tabs
+maps.n["]t"] = { function() vim.cmd.tabnext() end, desc = "Next tab" }
+maps.n["[t"] = { function() vim.cmd.tabprevious() end, desc = "Previous tab" }
+
+-- zen mode
+if is_available "zen-mode.nvim" then
+ maps.n["<leader>uz"] =
+ { function() ui.toggle_zen_mode() end, desc = "Zen mode" }
+end
+
+-- ui toggles [ui] ---------------------------------------------------------
+maps.n["<leader>u"] = icons.u
+if is_available "nvim-autopairs" then
+ maps.n["<leader>ua"] = { ui.toggle_autopairs, desc = "Autopairs" }
+end
+maps.n["<leader>ub"] = { ui.toggle_background, desc = "Background" }
+if is_available "nvim-cmp" then
+ maps.n["<leader>uc"] = { ui.toggle_cmp, desc = "Autocompletion" }
+end
+if is_available "nvim-colorizer.lua" then
+ maps.n["<leader>uC"] =
+ { "<cmd>ColorizerToggle<cr>", desc = "color highlight" }
+end
+maps.n["<leader>ud"] = { ui.toggle_diagnostics, desc = "Diagnostics" }
+maps.n["<leader>uD"] = { ui.set_indent, desc = "Change indent setting" }
+maps.n["<leader>ug"] = { ui.toggle_signcolumn, desc = "Signcolumn" }
+maps.n["<leader>ul"] = { ui.toggle_statusline, desc = "Statusline" }
+maps.n["<leader>un"] = { ui.change_number, desc = "Change line numbering" }
+maps.n["<leader>uP"] = { ui.toggle_paste, desc = "Paste mode" }
+maps.n["<leader>us"] = { ui.toggle_spell, desc = "Spellcheck" }
+maps.n["<leader>uS"] = { ui.toggle_conceal, desc = "Conceal" }
+maps.n["<leader>ut"] = { ui.toggle_tabline, desc = "Tabline" }
+maps.n["<leader>uu"] = { ui.toggle_url_effect, desc = "URL highlight" }
+maps.n["<leader>uw"] = { ui.toggle_wrap, desc = "Wrap" }
+maps.n["<leader>uy"] = { ui.toggle_buffer_syntax, desc = "Syntax highlight (buffer)" }
+maps.n["<leader>uh"] = { ui.toggle_foldcolumn, desc = "Foldcolumn" }
+maps.n["<leader>uN"] =
+{ ui.toggle_ui_notifications, desc = "UI notifications" }
+if is_available "lsp_signature.nvim" then
+ maps.n["<leader>up"] = { ui.toggle_lsp_signature, desc = "LSP signature" }
+end
+if is_available "mini.animate" then
+ maps.n["<leader>uA"] = { ui.toggle_animations, desc = "Animations" }
+end
+
+-- shifted movement keys ----------------------------------------------------
+maps.n["<S-Down>"] = {
+ function() vim.api.nvim_feedkeys("7j", "n", true) end,
+ desc = "Fast move down",
+}
+maps.n["<S-Up>"] = {
+ function() vim.api.nvim_feedkeys("7k", "n", true) end,
+ desc = "Fast move up",
+}
+maps.n["<S-PageDown>"] = {
+ function()
+ local current_line = vim.fn.line "."
+ local total_lines = vim.fn.line "$"
+ local target_line = current_line + 1 + math.floor(total_lines * 0.20)
+ if target_line > total_lines then target_line = total_lines end
+ vim.api.nvim_win_set_cursor(0, { target_line, 0 })
+ vim.cmd "normal! zz"
+ end,
+ desc = "Page down exactly a 20% of the total size of the buffer",
+}
+maps.n["<S-PageUp>"] = {
+ function()
+ local current_line = vim.fn.line "."
+ local target_line = current_line - 1 - math.floor(vim.fn.line "$" * 0.20)
+ if target_line < 1 then target_line = 1 end
+ vim.api.nvim_win_set_cursor(0, { target_line, 0 })
+ vim.cmd "normal! zz"
+ end,
+ desc = "Page up exactly 20% of the total size of the buffer",
+}
+
+-- cmdline autocompletion ---------------------------------------------------
+maps.c["<Up>"] = {
+ function() return vim.fn.wildmenumode() == 1 and "<Left>" or "<Up>" end,
+ noremap = true,
+ expr = true,
+ desc = "Wildmenu fix for neovim bug #9953",
+}
+maps.c["<Down>"] = {
+ function() return vim.fn.wildmenumode() == 1 and "<Right>" or "<Down>" end,
+ noremap = true,
+ expr = true,
+ desc = "Wildmenu fix for neovim bug #9953",
+}
+maps.c["<Left>"] = {
+ function() return vim.fn.wildmenumode() == 1 and "<Up>" or "<Left>" end,
+ noremap = true,
+ expr = true,
+ desc = "Wildmenu fix for neovim bug #9953",
+}
+maps.c["<Right>"] = {
+ function() return vim.fn.wildmenumode() == 1 and "<Down>" or "<Right>" end,
+ noremap = true,
+ expr = true,
+ desc = "Wildmenu fix for neovim bug #9953",
+}
+
+-- special cases ------------------------------------------------------------
+vim.api.nvim_create_autocmd("BufWinEnter", {
+ desc = "Make q close help, man, quickfix, dap floats",
+ callback = function(args)
+ local buftype =
+ vim.api.nvim_get_option_value("buftype", { buf = args.buf })
+ if vim.tbl_contains({ "help", "nofile", "quickfix" }, buftype) then
+ vim.keymap.set(
+ "n", "q", "<cmd>close<cr>",
+ { buffer = args.buf, silent = true, nowait = true }
+ )
+ end
+ end,
+})
+vim.api.nvim_create_autocmd("CmdwinEnter", {
+ desc = "Make q close command history (q: and q?)",
+ callback = function(args)
+ vim.keymap.set(
+ "n", "q", "<cmd>close<cr>",
+ { buffer = args.buf, silent = true, nowait = true }
+ )
+ end,
+})
+
+-- -------------------------------------------------------------------------
+--
+-- ## Plugin bindings
+--
+-- -------------------------------------------------------------------------
+
+-- alpha-nvim --------------------------------------------------------------
+if is_available "alpha-nvim" then
+ maps.n["<leader>h"] = {
+ function()
+ local wins = vim.api.nvim_tabpage_list_wins(0)
+ if #wins > 1
+ and vim.api.nvim_get_option_value("filetype", { win = wins[1] })
+ == "neo-tree"
+ then
+ vim.fn.win_gotoid(wins[2]) -- go to non-neo-tree window to toggle alpha
+ end
+ require("alpha").start(false, require("alpha").default_config)
+ vim.b.miniindentscope_disable = true
+ end,
+ desc = "Home screen",
+ }
+end
+
+-- [git] -----------------------------------------------------------
+-- gitsigns.nvim
+maps.n["<leader>g"] = icons.g
+if is_available "gitsigns.nvim" then
+ maps.n["<leader>g"] = icons.g
+ maps.n["]g"] =
+ { function() require("gitsigns").next_hunk() end, desc = "Next Git hunk" }
+ maps.n["[g"] = {
+ function() require("gitsigns").prev_hunk() end,
+ desc = "Previous Git hunk",
+ }
+ maps.n["<leader>gl"] = {
+ function() require("gitsigns").blame_line() end,
+ desc = "View Git blame",
+ }
+ maps.n["<leader>gL"] = {
+ function() require("gitsigns").blame_line { full = true } end,
+ desc = "View full Git blame",
+ }
+ maps.n["<leader>gp"] = {
+ function() require("gitsigns").preview_hunk() end,
+ desc = "Preview Git hunk",
+ }
+ maps.n["<leader>gh"] = {
+ function() require("gitsigns").reset_hunk() end,
+ desc = "Reset Git hunk",
+ }
+ maps.n["<leader>gr"] = {
+ function() require("gitsigns").reset_buffer() end,
+ desc = "Reset Git buffer",
+ }
+ maps.n["<leader>gs"] = {
+ function() require("gitsigns").stage_hunk() end,
+ desc = "Stage Git hunk",
+ }
+ maps.n["<leader>gS"] = {
+ function() require("gitsigns").stage_buffer() end,
+ desc = "Stage Git buffer",
+ }
+ maps.n["<leader>gu"] = {
+ function() require("gitsigns").undo_stage_hunk() end,
+ desc = "Unstage Git hunk",
+ }
+ maps.n["<leader>gd"] = {
+ function() require("gitsigns").diffthis() end,
+ desc = "View Git diff",
+ }
+end
+-- git fugitive
+if is_available "vim-fugitive" then
+ maps.n["<leader>gP"] = {
+ function() vim.cmd ":GBrowse" end,
+ desc = "Open in github ",
+ }
+end
+-- git client
+if vim.fn.executable "lazygit" == 1 then -- if lazygit exists, show it
+ maps.n["<leader>gg"] = {
+ function()
+ local git_dir = vim.fn.finddir(".git", vim.fn.getcwd() .. ";")
+ if git_dir ~= "" then
+ vim.cmd "TermExec cmd='lazygit && exit'"
+ else
+ utils.notify("Not a git repository", vim.log.levels.WARN)
+ end
+ end,
+ desc = "ToggleTerm lazygit",
+ }
+end
+if vim.fn.executable "gitui" == 1 then -- if gitui exists, show it
+ maps.n["<leader>gg"] = {
+ function()
+ local git_dir = vim.fn.finddir(".git", vim.fn.getcwd() .. ";")
+ if git_dir ~= "" then
+ if vim.fn.executable "keychain" == 1 then
+ vim.cmd 'TermExec cmd="eval `keychain --eval ~/.ssh/github.key` && gitui && exit"'
+ else
+ vim.cmd "TermExec cmd='gitui && exit'"
+ end
+ else
+ utils.notify("Not a git repository", vim.log.levels.WARN)
+ end
+ end,
+ desc = "ToggleTerm gitui",
+ }
+end
+
+-- file browsers ------------------------------------
+-- ranger
+if is_available "rnvimr" then
+ maps.n["<leader>r"] = { "<cmd>RnvimrToggle<cr>", desc = "Ranger" }
+end
+
+-- neotree
+if is_available "neo-tree.nvim" then
+ maps.n["<leader>e"] = { "<cmd>Neotree toggle<cr>", desc = "Neotree" }
+end
+
+-- session manager ---------------------------------------------------------
+if is_available "neovim-session-manager" then
+ maps.n["<leader>S"] = icons.S
+ maps.n["<leader>Sl"] = {
+ "<cmd>SessionManager! load_last_session<cr>",
+ desc = "Load last session",
+ }
+ maps.n["<leader>Ss"] = {
+ "<cmd>SessionManager! save_current_session<cr>",
+ desc = "Save this session",
+ }
+ maps.n["<leader>Sd"] =
+ { "<cmd>SessionManager! delete_session<cr>", desc = "Delete session" }
+ maps.n["<leader>Sf"] =
+ { "<cmd>SessionManager! load_session<cr>", desc = "Search sessions" }
+ maps.n["<leader>S."] = {
+ "<cmd>SessionManager! load_current_dir_session<cr>",
+ desc = "Load current directory session",
+ }
+end
+if is_available "resession.nvim" then
+ maps.n["<leader>S"] = icons.S
+ maps.n["<leader>Sl"] = {
+ function() require("resession").load "Last Session" end,
+ desc = "Load last session",
+ }
+ maps.n["<leader>Ss"] =
+ { function() require("resession").save() end, desc = "Save this session" }
+ maps.n["<leader>St"] = {
+ function() require("resession").save_tab() end,
+ desc = "Save this tab's session",
+ }
+ maps.n["<leader>Sd"] =
+ { function() require("resession").delete() end, desc = "Delete a session" }
+ maps.n["<leader>Sf"] =
+ { function() require("resession").load() end, desc = "Load a session" }
+ maps.n["<leader>S."] = {
+ function()
+ require("resession").load(vim.fn.getcwd(), { dir = "dirsession" })
+ end,
+ desc = "Load current directory session",
+ }
+end
+
+-- smart-splits.nivm
+if is_available "smart-splits.nvim" then
+ maps.n["<C-h>"] = {
+ function() require("smart-splits").move_cursor_left() end,
+ desc = "Move to left split",
+ }
+ maps.n["<C-j>"] = {
+ function() require("smart-splits").move_cursor_down() end,
+ desc = "Move to below split",
+ }
+ maps.n["<C-k>"] = {
+ function() require("smart-splits").move_cursor_up() end,
+ desc = "Move to above split",
+ }
+ maps.n["<C-l>"] = {
+ function() require("smart-splits").move_cursor_right() end,
+ desc = "Move to right split",
+ }
+ maps.n["<C-Up>"] = {
+ function() require("smart-splits").resize_up() end,
+ desc = "Resize split up",
+ }
+ maps.n["<C-Down>"] = {
+ function() require("smart-splits").resize_down() end,
+ desc = "Resize split down",
+ }
+ maps.n["<C-Left>"] = {
+ function() require("smart-splits").resize_left() end,
+ desc = "Resize split left",
+ }
+ maps.n["<C-Right>"] = {
+ function() require("smart-splits").resize_right() end,
+ desc = "Resize split right",
+ }
+else
+ maps.n["<C-h>"] = { "<C-w>h", desc = "Move to left split" }
+ maps.n["<C-j>"] = { "<C-w>j", desc = "Move to below split" }
+ maps.n["<C-k>"] = { "<C-w>k", desc = "Move to above split" }
+ maps.n["<C-l>"] = { "<C-w>l", desc = "Move to right split" }
+ maps.n["<C-Up>"] = { "<cmd>resize -2<CR>", desc = "Resize split up" }
+ maps.n["<C-Down>"] = { "<cmd>resize +2<CR>", desc = "Resize split down" }
+ maps.n["<C-Left>"] =
+ { "<cmd>vertical resize -2<CR>", desc = "Resize split left" }
+ maps.n["<C-Right>"] =
+ { "<cmd>vertical resize +2<CR>", desc = "Resize split right" }
+end
+
+-- aerial.nvimm ------------------------------------------------------------
+if is_available "aerial.nvim" then
+ maps.n["<leader>i"] =
+ { function() require("aerial").toggle() end, desc = "Aerial" }
+end
+
+-- letee-calltree.nvimm ------------------------------------------------------------
+if is_available "litee-calltree.nvim" then
+ -- For every buffer, look for the one with filetype "calltree" and focus it.
+ local calltree_delay = 1500 -- first run? wait a bit longer.
+ local function focus_calltree()
+ -- Note: No go to the previous cursor position, press ctrl+i / ctrl+o
+ vim.defer_fn(function()
+ for _, win in ipairs(vim.api.nvim_list_wins()) do
+ local buf = vim.api.nvim_win_get_buf(win)
+ local ft = vim.api.nvim_get_option_value('filetype', { buf = buf })
+
+ if ft == "calltree" then
+ vim.api.nvim_set_current_win(win)
+ return true
+ end
+ end
+ end, calltree_delay)
+ calltree_delay = 100
+ end
+ maps.n["gj"] = {
+ function()
+ vim.lsp.buf.incoming_calls()
+ focus_calltree()
+ end,
+ desc = "Call tree (incoming)"
+ }
+ maps.n["gJ"] =
+ {
+ function()
+ vim.lsp.buf.outgoing_calls()
+ focus_calltree()
+ end,
+ desc = "Call tree (outgoing)"
+ }
+end
+
+-- telescope.nvim [find] ----------------------------------------------------
+if is_available "telescope.nvim" then
+ maps.n["<leader>f"] = icons.f
+ maps.n["<leader>gb"] = {
+ function() require("telescope.builtin").git_branches() end,
+ desc = "Git branches",
+ }
+ maps.n["<leader>gc"] = {
+ function()
+ require("telescope.builtin").git_commits()
+ end,
+ desc = "Git commits (repository)"
+ }
+ maps.n["<leader>gC"] = {
+ function()
+ require("telescope.builtin").git_bcommits()
+ end,
+ desc = "Git commits (current file)"
+ }
+ maps.n["<leader>gt"] = {
+ function() require("telescope.builtin").git_status() end,
+ desc = "Git status",
+ }
+ maps.n["<leader>f<CR>"] = {
+ function() require("telescope.builtin").resume() end,
+ desc = "Resume previous search",
+ }
+ maps.n["<leader>f'"] = {
+ function() require("telescope.builtin").marks() end,
+ desc = "Find marks",
+ }
+ maps.n["<leader>fa"] = {
+ function()
+ local cwd = vim.fn.stdpath "config" .. "/.."
+ local search_dirs = { vim.fn.stdpath "config" }
+ if #search_dirs == 1 then cwd = search_dirs[1] end -- if only one directory, focus cwd
+ require("telescope.builtin").find_files {
+ prompt_title = "Config Files",
+ search_dirs = search_dirs,
+ cwd = cwd,
+ follow = true,
+ } -- call telescope
+ end,
+ desc = "Find nvim config files",
+ }
+ maps.n["<leader>fB"] = {
+ function() require("telescope.builtin").buffers() end,
+ desc = "Find buffers",
+ }
+ maps.n["<leader>fw"] = {
+ function() require("telescope.builtin").grep_string() end,
+ desc = "Find word under cursor in project",
+ }
+ maps.n["<leader>fC"] = {
+ function() require("telescope.builtin").commands() end,
+ desc = "Find commands",
+ }
+ -- Let's disable this. It is way too imprecise. Use rnvimr instead.
+ -- maps.n["<leader>ff"] = {
+ -- function()
+ -- require("telescope.builtin").find_files { hidden = true, no_ignore = true }
+ -- end,
+ -- desc = "Find all files",
+ -- }
+ -- maps.n["<leader>fF"] = {
+ -- function() require("telescope.builtin").find_files() end,
+ -- desc = "Find files (no hidden)",
+ -- }
+ maps.n["<leader>fh"] = {
+ function() require("telescope.builtin").help_tags() end,
+ desc = "Find help",
+ }
+ maps.n["<leader>fk"] = {
+ function() require("telescope.builtin").keymaps() end,
+ desc = "Find keymaps",
+ }
+ maps.n["<leader>fm"] = {
+ function() require("telescope.builtin").man_pages() end,
+ desc = "Find man",
+ }
+ if is_available "nvim-notify" then
+ maps.n["<leader>fn"] = {
+ function() require("telescope").extensions.notify.notify() end,
+ desc = "Find notifications",
+ }
+ end
+ maps.n["<leader>fo"] = {
+ function() require("telescope.builtin").oldfiles() end,
+ desc = "Find recent",
+ }
+ maps.n["<leader>fv"] = {
+ function() require("telescope.builtin").registers() end,
+ desc = "Find vim registers",
+ }
+ maps.n["<leader>ft"] = {
+ function()
+ -- load color schemes before listing them
+ pcall(vim.api.nvim_command, "doautocmd User LoadColorSchemes")
+
+ -- Open telescope
+ pcall(require("telescope.builtin").colorscheme, {
+ enable_preview = true,
+ ignore_builtins = true
+ })
+ end,
+ desc = "Find themes",
+ }
+ maps.n["<leader>ff"] = {
+ function()
+ require("telescope.builtin").live_grep {
+ additional_args = function(args)
+ return vim.list_extend(args, { "--hidden", "--no-ignore" })
+ end,
+ }
+ end,
+ desc = "Find words in project",
+ }
+ maps.n["<leader>fF"] = {
+ function() require("telescope.builtin").live_grep() end,
+ desc = "Find words in project (no hidden)",
+ }
+ maps.n["<leader>f/"] = {
+ function() require("telescope.builtin").current_buffer_fuzzy_find() end,
+ desc = "Find words in current buffer"
+ }
+
+ -- Some lsp keymappings are here because they depend on telescope
+ maps.n["<leader>l"] = icons.l
+ maps.n["<leader>ls"] = {
+ function()
+ local aerial_avail, _ = pcall(require, "aerial")
+ if aerial_avail then
+ require("telescope").extensions.aerial.aerial()
+ else
+ require("telescope.builtin").lsp_document_symbols()
+ end
+ end,
+ desc = "Search symbol in buffer", -- Useful to find every time a variable is assigned.
+ }
+ maps.n["gs"] = {
+ function()
+ local aerial_avail, _ = pcall(require, "aerial")
+ if aerial_avail then
+ require("telescope").extensions.aerial.aerial()
+ else
+ require("telescope.builtin").lsp_document_symbols()
+ end
+ end,
+ desc = "Search symbol in buffer", -- Useful to find every time a variable is assigned.
+ }
+
+ -- extra - project.nvim
+ if is_available "project.nvim" then
+ maps.n["<leader>fp"] = {
+ function() vim.cmd "Telescope projects" end,
+ desc = "Find project",
+ }
+ end
+
+ -- extra - spectre.nvim (search and replace in project)
+ if is_available "nvim-spectre" then
+ maps.n["<leader>fr"] = {
+ function() require("spectre").toggle() end,
+ desc = "Find and replace word in project",
+ }
+ maps.n["<leader>fb"] = {
+ function() require("spectre").toggle { path = vim.fn.expand "%:t:p" } end,
+ desc = "Find and replace word in buffer",
+ }
+ end
+
+ -- extra - luasnip
+ if is_available "LuaSnip" and is_available "telescope-luasnip.nvim" then
+ maps.n["<leader>fs"] = {
+ function() require("telescope").extensions.luasnip.luasnip {} end,
+ desc = "Find snippets",
+ }
+ end
+
+ -- extra - nvim-neoclip (neovim internal clipboard)
+ -- Specially useful if you disable the shared clipboard in options.
+ if is_available "nvim-neoclip.lua" then
+ maps.n["<leader>fy"] = {
+ function() require("telescope").extensions.neoclip.default() end,
+ desc = "Find yank history",
+ }
+ maps.n["<leader>fq"] = {
+ function() require("telescope").extensions.macroscope.default() end,
+ desc = "Find macro history",
+ }
+ end
+
+ -- extra - undotree
+ if is_available "telescope-undo.nvim" then
+ maps.n["<leader>fu"] = {
+ function() require("telescope").extensions.undo.undo() end,
+ desc = "Find in undo tree",
+ }
+ end
+
+ -- extra - compiler
+ if is_available "compiler.nvim" and is_available "overseer.nvim" then
+ maps.n["<leader>m"] = icons.c
+ maps.n["<leader>mm"] = {
+ function() vim.cmd "CompilerOpen" end,
+ desc = "Open compiler",
+ }
+ maps.n["<leader>mr"] = {
+ function() vim.cmd "CompilerRedo" end,
+ desc = "Compiler redo",
+ }
+ maps.n["<leader>mt"] = {
+ function() vim.cmd "CompilerToggleResults" end,
+ desc = "compiler results",
+ }
+ maps.n["<F6>"] = {
+ function() vim.cmd "CompilerOpen" end,
+ desc = "Open compiler",
+ }
+ maps.n["<S-F6>"] = {
+ function() vim.cmd "CompilerRedo" end,
+ desc = "Compiler redo",
+ }
+ maps.n["<S-F7>"] = {
+ function() vim.cmd "CompilerToggleResults" end,
+ desc = "compiler resume",
+ }
+ end
+end
+
+-- toggleterm.nvim ----------------------------------------------------------
+if is_available "toggleterm.nvim" then
+ maps.n["<leader>t"] = icons.t
+ maps.n["<leader>tt"] =
+ { "<cmd>ToggleTerm direction=float<cr>", desc = "ToggleTerm float" }
+ maps.n["<leader>th"] = {
+ "<cmd>ToggleTerm size=10 direction=horizontal<cr>",
+ desc = "Toggleterm horizontal split",
+ }
+ maps.n["<leader>tv"] = {
+ "<cmd>ToggleTerm size=80 direction=vertical<cr>",
+ desc = "Toggleterm vertical split",
+ }
+ maps.n["<F7>"] = { "<cmd>ToggleTerm<cr>", desc = "terminal" }
+ maps.t["<F7>"] = maps.n["<F7>"]
+ maps.n["<C-'>"] = maps.n["<F7>"] -- requires terminal that supports binding <C-'>
+ maps.t["<C-'>"] = maps.n["<F7>"] -- requires terminal that supports binding <C-'>
+end
+
+-- extra - improved terminal navigation
+maps.t["<C-h>"] =
+{ "<cmd>wincmd h<cr>", desc = "Terminal left window navigation" }
+maps.t["<C-j>"] =
+{ "<cmd>wincmd j<cr>", desc = "Terminal down window navigation" }
+maps.t["<C-k>"] =
+{ "<cmd>wincmd k<cr>", desc = "Terminal up window navigation" }
+maps.t["<C-l>"] =
+{ "<cmd>wincmd l<cr>", desc = "Terminal right window navigation" }
+
+-- dap.nvim [debugger] -----------------------------------------------------
+-- Depending your terminal some F keys may not work. To fix it:
+-- modified function keys found with `showkey -a` in the terminal to get key code
+-- run `nvim -V3log +quit` and search through the "Terminal info" in the `log` file for the correct keyname
+if is_available "nvim-dap" then
+ maps.n["<leader>d"] = icons.d
+ maps.x["<leader>d"] = icons.d
+
+ -- F keys
+ maps.n["<F5>"] = {
+ function()
+ require("dap").continue()
+ end,
+ desc = "Debugger: Start"
+ }
+ maps.n["<S-F5>"] =
+ { function() require("dap").terminate() end, desc = "Debugger: Stop" }
+ maps.n["<C-F5>"] = {
+ function() require("dap").restart_frame() end, desc = "Debugger: Restart" }
+ maps.n["<F9>"] = {
+ function() require("dap").toggle_breakpoint() end, desc = "Debugger: Toggle Breakpoint" }
+ maps.n["<S-F9>"] = {
+ function()
+ vim.ui.input({ prompt = "Condition: " }, function(condition)
+ if condition then require("dap").set_breakpoint(condition) end
+ end)
+ end,
+ desc = "Debugger: Conditional Breakpoint",
+ }
+ maps.n["<F10>"] =
+ { function() require("dap").step_over() end, desc = "Debugger: Step Over" }
+ maps.n["<S-F10>"] =
+ { function() require("dap").step_back() end, desc = "Debugger: Step Back" }
+ maps.n["<F11>"] =
+ { function() require("dap").step_into() end, desc = "Debugger: Step Into" }
+ maps.n["<S-11>"] =
+ { function() require("dap").step_out() end, desc = "Debugger: Step Out" }
+
+ -- Space + d
+ maps.n["<leader>db"] = {
+ function() require("dap").toggle_breakpoint() end,
+ desc = "Breakpoint (F9)",
+ }
+ maps.n["<leader>dB"] = {
+ function() require("dap").clear_breakpoints() end,
+ desc = "Clear Breakpoints",
+ }
+ maps.n["<leader>dc"] =
+ { function() require("dap").continue() end, desc = "Start/Continue (F5)" }
+ maps.n["<leader>dC"] = {
+ function()
+ vim.ui.input({ prompt = "Condition: " }, function(condition)
+ if condition then require("dap").set_breakpoint(condition) end
+ end)
+ end,
+ desc = "Conditional Breakpoint (S-F9)",
+ }
+ maps.n["<leader>do"] =
+ { function() require("dap").step_over() end, desc = "Step Over (F10)" }
+ maps.n["<leader>do"] =
+ { function() require("dap").step_back() end, desc = "Step Back (S-F10)" }
+ maps.n["<leader>db"] =
+ { function() require("dap").step_into() end, desc = "Step Into (F11)" }
+ maps.n["<leader>dO"] =
+ { function() require("dap").step_out() end, desc = "Step Out (S-F11)" }
+ maps.n["<leader>dq"] =
+ { function() require("dap").close() end, desc = "Close Session" }
+ maps.n["<leader>dQ"] = {
+ function() require("dap").terminate() end,
+ desc = "Terminate Session (S-F5)",
+ }
+ maps.n["<leader>dp"] =
+ { function() require("dap").pause() end, desc = "Pause" }
+ maps.n["<leader>dr"] =
+ { function() require("dap").restart_frame() end, desc = "Restart (C-F5)" }
+ maps.n["<leader>dR"] =
+ { function() require("dap").repl.toggle() end, desc = "REPL" }
+ maps.n["<leader>ds"] =
+ { function() require("dap").run_to_cursor() end, desc = "Run To Cursor" }
+
+ if is_available "nvim-dap-ui" then
+ maps.n["<leader>dE"] = {
+ function()
+ vim.ui.input({ prompt = "Expression: " }, function(expr)
+ if expr then require("dapui").eval(expr, { enter = true }) end
+ end)
+ end,
+ desc = "Evaluate Input",
+ }
+ maps.x["<leader>dE"] =
+ { function() require("dapui").eval() end, desc = "Evaluate Input" }
+ maps.n["<leader>du"] =
+ { function() require("dapui").toggle() end, desc = "Debugger UI" }
+ maps.n["<leader>dh"] = {
+ function() require("dap.ui.widgets").hover() end,
+ desc = "Debugger Hover",
+ }
+ end
+end
+
+-- testing [tests] -------------------------------------------------
+-- neotest
+maps.n["<leader>T"] = icons.tt
+maps.x["<leader>T"] = icons.tt
+if is_available "neotest" then
+ maps.n["<leader>Tu"] = {
+ function() require("neotest").run.run() end,
+ desc = "Unit",
+ }
+ maps.n["<leader>Ts"] = {
+ function() require("neotest").run.stop() end,
+ desc = "Stop unit",
+ }
+ maps.n["<leader>Tf"] = {
+ function() require("neotest").run.run(vim.fn.expand "%") end,
+ desc = "File",
+ }
+ maps.n["<leader>Td"] = {
+ function() require("neotest").run.run { strategy = "dap" } end,
+ desc = "Unit in debugger",
+ }
+ maps.n["<leader>Tt"] = {
+ function() require("neotest").summary.toggle() end,
+ desc = "Neotest summary",
+ }
+ maps.n["<leader>TT"] = {
+ function() require("neotest").output_panel.toggle() end,
+ desc = "Output panel",
+ }
+end
+
+-- Extra - nvim-coverage
+-- Your project must generate coverage/lcov.info for this to work.
+--
+-- On jest, make sure your packages.json file has this:
+-- "test": "jest --coverage"
+--
+-- If you use other framework or language, refer to nvim-coverage docs:
+-- https://github.com/andythigpen/nvim-coverage/blob/main/doc/nvim-coverage.txt
+if is_available "nvim-coverage" then
+ maps.n["<leader>Tc"] = {
+ function()
+ require("coverage").load(false)
+ require("coverage").summary()
+ end,
+ desc = "Coverage",
+ }
+ maps.n["<leader>TC"] = {
+ function()
+ ui.toggle_coverage_signs()
+ end,
+ desc = "Coverage signs (toggle)",
+ }
+end
+
+-- Extra - nodejs testing commands
+maps.n["<leader>Ta"] = {
+ function() vim.cmd "TestNodejs" end,
+ desc = "All",
+}
+maps.n["<leader>Te"] = {
+ function() vim.cmd "TestNodejsE2e" end,
+ desc = "E2e",
+}
+
+-- nvim-ufo [code folding] --------------------------------------------------
+if is_available "nvim-ufo" then
+ maps.n["zR"] =
+ { function() require("ufo").openAllFolds() end, desc = "Open all folds" }
+ maps.n["zM"] =
+ { function() require("ufo").closeAllFolds() end, desc = "Close all folds" }
+ maps.n["zr"] = {
+ function() require("ufo").openFoldsExceptKinds() end,
+ desc = "Fold less",
+ }
+ maps.n["zm"] =
+ { function() require("ufo").closeFoldsWith() end, desc = "Fold more" }
+ maps.n["zp"] = {
+ function() require("ufo").peekFoldedLinesUnderCursor() end,
+ desc = "Peek fold",
+ }
+ maps.n["zn"] =
+ {
+ function() require("ufo").openFoldsExceptKinds({ 'comment' }) end,
+ desc = "Fold comments"
+ }
+ maps.n["zN"] =
+ {
+ function() require("ufo").openFoldsExceptKinds({ 'region' }) end,
+ desc = "Fold region"
+ }
+end
+
+-- code docmentation [docs] -------------------------------------------------
+
+if is_available "markdown-preview.nivm" or is_available "markmap.nvim" or is_available "dooku.nvim" then
+ maps.n["<leader>D"] = icons.dc
+
+ -- Markdown preview
+ if is_available "markdown-preview.nvim" then
+ maps.n["<leader>Dp"] = {
+ function() vim.cmd "MarkdownPreview" end,
+ desc = "Markdown preview",
+ }
+ end
+
+ -- Markdown Mindmap
+ if is_available "markmap.nvim" then
+ maps.n["<leader>Dm"] = {
+ function()
+ if is_android then
+ vim.cmd "MarkmapWatch"
+ else
+ vim.cmd "MarkmapOpen"
+ end
+ end,
+ desc = "Markmap",
+ }
+ end
+
+ if is_available "dooku.nvim" then
+ maps.n["<leader>Dd"] = {
+ function() vim.cmd ":DookuGenerate" end,
+ desc = "Open documentation",
+ }
+ end
+end
+
+-- [neural] -----------------------------------------------------------------
+if is_available "neural" or is_available "copilot" then
+ maps.n["<leader>a"] = {
+ function() require("neural").prompt() end,
+ desc = "Ask chatgpt",
+ }
+end
+
+-- hop.nivm ----------------------------------------------------------------
+if is_available "hop.nvim" then
+ -- Note that Even though we are using ENTER for hop, you can still select items
+ -- from special menus like 'quickfix', 'q?' and 'q:' with <C+ENTER>.
+
+ maps.n["<C-m>"] = { -- The terminal undersand C-m and ENTER as the same key.
+ function()
+ require("hop")
+ vim.cmd("silent! HopWord")
+ end,
+ desc = "Hop to word",
+ }
+ maps.x["<C-m>"] = { -- The terminal undersand C-m and ENTER as the same key.
+ function()
+ require("hop")
+ vim.cmd("silent! HopWord")
+ end,
+ desc = "Hop to word",
+ }
+end
+
+-- mason-lspconfig.nvim [lsp] -------------------------------------------------
+-- WARNING: Don't delete this section, or you won't have LSP keymappings.
+
+--A function we call from the script to start lsp.
+--@return table lsp_mappings
+function M.lsp_mappings(client, bufnr)
+ -- Helper function to check if any active LSP clients
+ -- given a filter provide a specific capability.
+ -- @param capability string The server capability to check for (example: "documentFormattingProvider").
+ -- @param filter vim.lsp.get_clients.filter|nil A valid get_clients filter (see function docs).
+ -- @return boolean # `true` if any of the clients provide the capability.
+ local function has_capability(capability, filter)
+ for _, lsp_client in ipairs(vim.lsp.get_clients(filter)) do
+ if lsp_client.supports_method(capability) then return true end
+ end
+ return false
+ end
+
+ local lsp_mappings = require("base.utils").get_mappings_template()
+
+ -- Diagnostics
+ lsp_mappings.n["<leader>ld"] = { function() vim.diagnostic.open_float() end, desc = "Hover diagnostics" }
+ lsp_mappings.n["[d"] = { function()
+ -- TODO: Delete after dropping nvim 0.10 support.
+ if vim.fn.has('nvim-0.11') == 1 then vim.diagnostic.jump({ count = -1 })
+ else vim.diagnostic.goto_prev() end end, desc = "Previous diagnostic"
+ }
+ lsp_mappings.n["]d"] = { function()
+ -- TODO: Delete after dropping nvim 0.10 support.
+ if vim.fn.has('nvim-0.11') == 1 then vim.diagnostic.jump({ count = 1 })
+ else vim.diagnostic.goto_next() end end, desc = "Next diagnostic" }
+
+ -- Diagnostics
+ lsp_mappings.n["gl"] = { function() vim.diagnostic.open_float() end, desc = "Hover diagnostics" }
+ if is_available "telescope.nvim" then
+ lsp_mappings.n["<leader>lD"] =
+ { function() require("telescope.builtin").diagnostics() end, desc = "Diagnostics" }
+ end
+
+ -- LSP info
+ if is_available "mason-lspconfig.nvim" then
+ lsp_mappings.n["<leader>li"] = { "<cmd>LspInfo<cr>", desc = "LSP information" }
+ end
+
+ if is_available "none-ls.nvim" then
+ lsp_mappings.n["<leader>lI"] = { "<cmd>NullLsInfo<cr>", desc = "Null-ls information" }
+ end
+
+ -- Code actions
+ lsp_mappings.n["<leader>la"] = {
+ function() vim.lsp.buf.code_action() end,
+ desc = "LSP code action",
+ }
+ lsp_mappings.v["<leader>la"] = lsp_mappings.n["<leader>la"]
+
+ -- Codelens
+ utils.add_autocmds_to_buffer("lsp_codelens_refresh", bufnr, {
+ events = { "InsertLeave" },
+ desc = "Refresh codelens",
+ callback = function(args)
+ if client.supports_method "textDocument/codeLens" then
+ if vim.g.codelens_enabled then vim.lsp.codelens.refresh({ bufnr = args.buf }) end
+ end
+ end,
+ })
+ if client.supports_method "textDocument/codeLens" then -- on LspAttach
+ if vim.g.codelens_enabled then vim.lsp.codelens.refresh({ bufnr = 0 }) end
+ end
+
+ lsp_mappings.n["<leader>ll"] = {
+ function()
+ vim.lsp.codelens.run()
+ vim.lsp.codelens.refresh({ bufnr = 0 })
+ end,
+ desc = "LSP CodeLens run",
+ }
+ lsp_mappings.n["<leader>uL"] = {
+ function() ui.toggle_codelens() end,
+ desc = "CodeLens",
+ }
+
+ -- Formatting
+ local formatting = require("base.utils.lsp").formatting
+ lsp_mappings.n["<leader>lf"] = {
+ function()
+ vim.lsp.buf.format(M.format_opts)
+ vim.cmd('checktime') -- update buffer to reflect changes.
+ end,
+ desc = "Format buffer",
+ }
+ lsp_mappings.v["<leader>lf"] = lsp_mappings.n["<leader>lf"]
+
+ vim.api.nvim_buf_create_user_command(
+ bufnr,
+ "Format",
+ function() vim.lsp.buf.format(M.format_opts) end,
+ { desc = "Format file with LSP" }
+ )
+ local autoformat = formatting.format_on_save
+ local filetype = vim.api.nvim_get_option_value("filetype", { buf = bufnr })
+ if
+ autoformat.enabled
+ and (vim.tbl_isempty(autoformat.allow_filetypes or {}) or vim.tbl_contains(autoformat.allow_filetypes, filetype))
+ and (vim.tbl_isempty(autoformat.ignore_filetypes or {}) or not vim.tbl_contains(autoformat.ignore_filetypes, filetype))
+ then
+ utils.add_autocmds_to_buffer("lsp_auto_format", bufnr, {
+ events = "BufWritePre",
+ desc = "Autoformat on save",
+ callback = function()
+ if not has_capability("textDocument/formatting", { bufnr = bufnr }) then
+ utils.del_autocmds_from_buffer("lsp_auto_format", bufnr)
+ return
+ end
+ local autoformat_enabled = vim.b.autoformat_enabled
+ if autoformat_enabled == nil then autoformat_enabled = vim.g.autoformat_enabled end
+ if autoformat_enabled and ((not autoformat.filter) or autoformat.filter(bufnr)) then
+ vim.lsp.buf.format(vim.tbl_deep_extend("force", M.format_opts, { bufnr = bufnr }))
+ end
+ end,
+ })
+ lsp_mappings.n["<leader>uf"] = {
+ function() require("base.utils.ui").toggle_buffer_autoformat() end,
+ desc = "Autoformatting (buffer)",
+ }
+ lsp_mappings.n["<leader>uF"] = {
+ function() require("base.utils.ui").toggle_autoformat() end,
+ desc = "Autoformatting (global)",
+ }
+ end
+
+ -- Highlight references when cursor holds
+ utils.add_autocmds_to_buffer("lsp_document_highlight", bufnr, {
+ {
+ events = { "CursorHold", "CursorHoldI" },
+ desc = "highlight references when cursor holds",
+ callback = function()
+ if has_capability("textDocument/documentHighlight", { bufnr = bufnr }) then
+ vim.lsp.buf.document_highlight()
+ end
+ end,
+ },
+ {
+ events = { "CursorMoved", "CursorMovedI", "BufLeave" },
+ desc = "clear references when cursor moves",
+ callback = function() vim.lsp.buf.clear_references() end,
+ },
+ })
+
+ -- Other LSP mappings
+ lsp_mappings.n["<leader>lL"] = {
+ function() vim.api.nvim_command(':LspRestart') end,
+ desc = "LSP refresh",
+ }
+
+ -- Goto definition / declaration
+ lsp_mappings.n["gd"] = {
+ function() vim.lsp.buf.definition() end,
+ desc = "Goto definition of current symbol",
+ }
+ lsp_mappings.n["gD"] = {
+ function() vim.lsp.buf.declaration() end,
+ desc = "Goto declaration of current symbol",
+ }
+
+ -- Goto implementation
+ lsp_mappings.n["gI"] = {
+ function() vim.lsp.buf.implementation() end,
+ desc = "Goto implementation of current symbol",
+ }
+
+ -- Goto type definition
+ lsp_mappings.n["gT"] = {
+ function() vim.lsp.buf.type_definition() end,
+ desc = "Goto definition of current type",
+ }
+
+ -- Goto references
+ lsp_mappings.n["<leader>lR"] = {
+ function() vim.lsp.buf.references() end,
+ desc = "Hover references",
+ }
+ lsp_mappings.n["gr"] = {
+ function() vim.lsp.buf.references() end,
+ desc = "References of current symbol",
+ }
+
+ -- Goto help
+ lsp_mappings.n["gh"] = {
+ function() vim.lsp.buf.hover() end,
+ desc = "Hover help",
+ }
+ lsp_mappings.n["gH"] = {
+ function() vim.lsp.buf.signature_help() end,
+ desc = "Signature help",
+ }
+
+ lsp_mappings.n["<leader>lh"] = {
+ function() vim.lsp.buf.hover() end,
+ desc = "Hover help",
+ }
+ lsp_mappings.n["<leader>lH"] = {
+ function() vim.lsp.buf.signature_help() end,
+ desc = "Signature help",
+ }
+
+ -- Goto man
+ lsp_mappings.n["gm"] = {
+ function() vim.api.nvim_feedkeys("K", "n", false) end,
+ desc = "Hover man",
+ }
+ lsp_mappings.n["<leader>lm"] = {
+ function() vim.api.nvim_feedkeys("K", "n", false) end,
+ desc = "Hover man",
+ }
+
+ -- Rename symbol
+ lsp_mappings.n["<leader>lr"] = {
+ function() vim.lsp.buf.rename() end,
+ desc = "Rename current symbol",
+ }
+
+ -- Toggle inlay hints
+ if vim.b.inlay_hints_enabled == nil then vim.b.inlay_hints_enabled = vim.g.inlay_hints_enabled end
+ if vim.b.inlay_hints_enabled then vim.lsp.inlay_hint.enable(true, { bufnr = bufnr }) end
+ lsp_mappings.n["<leader>uH"] = {
+ function() require("base.utils.ui").toggle_buffer_inlay_hints(bufnr) end,
+ desc = "LSP inlay hints (buffer)",
+ }
+
+ -- Toggle semantic tokens
+ if vim.g.semantic_tokens_enabled then
+ vim.b[bufnr].semantic_tokens_enabled = true
+ lsp_mappings.n["<leader>uY"] = {
+ function() require("base.utils.ui").toggle_buffer_semantic_tokens(bufnr) end,
+ desc = "LSP semantic highlight (buffer)",
+ }
+ else
+ client.server_capabilities.semanticTokensProvider = nil
+ end
+
+ -- LSP based search
+ lsp_mappings.n["<leader>lS"] = { function() vim.lsp.buf.workspace_symbol() end, desc = "Search symbol in workspace" }
+ lsp_mappings.n["gS"] = { function() vim.lsp.buf.workspace_symbol() end, desc = "Search symbol in workspace" }
+
+ -- LSP telescope
+ if is_available "telescope.nvim" then -- setup telescope mappings if available
+ if lsp_mappings.n.gd then lsp_mappings.n.gd[1] = function() require("telescope.builtin").lsp_definitions() end end
+ if lsp_mappings.n.gI then
+ lsp_mappings.n.gI[1] = function() require("telescope.builtin").lsp_implementations() end
+ end
+ if lsp_mappings.n.gr then lsp_mappings.n.gr[1] = function() require("telescope.builtin").lsp_references() end end
+ if lsp_mappings.n["<leader>lR"] then
+ lsp_mappings.n["<leader>lR"][1] = function() require("telescope.builtin").lsp_references() end
+ end
+ if lsp_mappings.n.gy then
+ lsp_mappings.n.gy[1] = function() require("telescope.builtin").lsp_type_definitions() end
+ end
+ if lsp_mappings.n["<leader>lS"] then
+ lsp_mappings.n["<leader>lS"][1] = function()
+ vim.ui.input({ prompt = "Symbol Query: (leave empty for word under cursor)" }, function(query)
+ if query then
+ -- word under cursor if given query is empty
+ if query == "" then query = vim.fn.expand "<cword>" end
+ require("telescope.builtin").lsp_workspace_symbols {
+ query = query,
+ prompt_title = ("Find word (%s)"):format(query),
+ }
+ end
+ end)
+ end
+ end
+ if lsp_mappings.n["gS"] then
+ lsp_mappings.n["gS"][1] = function()
+ vim.ui.input({ prompt = "Symbol Query: (leave empty for word under cursor)" }, function(query)
+ if query then
+ -- word under cursor if given query is empty
+ if query == "" then query = vim.fn.expand "<cword>" end
+ require("telescope.builtin").lsp_workspace_symbols {
+ query = query,
+ prompt_title = ("Find word (%s)"):format(query),
+ }
+ end
+ end)
+ end
+ end
+ end
+
+ return lsp_mappings
+end
+
+utils.set_mappings(maps)
+return M
@@ -0,0 +1,270 @@
+-- Command to check if you have the required dependencies to use NormalNvim.
+--
+-- DESCRIPTION:
+-- To use it run the command :healthcheck base
+
+local M = {}
+
+local health = {
+ start = vim.health.start or vim.health.report_start,
+ ok = vim.health.ok or vim.health.report_ok,
+ warn = vim.health.warn or vim.health.report_warn,
+ error = vim.health.error or vim.health.report_error,
+ info = vim.health.info or vim.health.report_info,
+}
+
+function M.check()
+ health.start "NormalNvim"
+
+ health.info(
+ "NormalNvim Version: " .. require("distroupdate.utils.updater").version(true)
+ )
+ health.info(
+ "Neovim Version: v"
+ .. vim.fn.matchstr(vim.fn.execute "version", "NVIM v\\zs[^\n]*")
+ )
+
+ if vim.version().prerelease then
+ health.warn "Neovim nightly is not officially supported and may have breaking changes"
+ elseif vim.fn.has "nvim-0.9" == 1 then
+ health.ok "Using stable Neovim >= 0.9.0"
+ else
+ health.error "Neovim >= 0.9.0 is required"
+ end
+
+ -- Checks to perform.
+ local programs = {
+ {
+ cmd = { "git" },
+ type = "error",
+ msg = "Used for core functionality such as updater and plugin management.",
+ },
+ {
+ cmd = { "luarocks" },
+ type = "error",
+ msg = "Used for core functionality such as updater and plugin management.",
+ },
+ {
+ cmd = { "node" },
+ type = "error",
+ msg = "Used for core functionality such as updater and plugin management.",
+ },
+ {
+ cmd = { "yarn" },
+ type = "error",
+ msg = "Used for core functionality such as updater and plugin management.",
+ },
+ {
+ cmd = { "cargo" },
+ type = "error",
+ msg = "Used by nvim-spectre to install oxi. Also by dooku.nvim to generate rust html docs.",
+ },
+ {
+ cmd = { "markmap" },
+ type = "warn",
+ msg = "Used by markmap.nvim. Make sure yarn is in your PATH. To learn how check markmap.nvim github page.",
+ },
+ {
+ cmd = { "fd" },
+ type = "error",
+ msg = "Used for nvim-spectre to find using fd.",
+ },
+ {
+ cmd = { "lazygit" },
+ type = "warn",
+ msg = "Used for mappings to pull up git TUI (Optional)",
+ },
+ {
+ cmd = { "gitui" },
+ type = "warn",
+ msg = "Used for mappings to pull up git TUI (Optional)",
+ },
+ {
+ cmd = { "pynvim" },
+ type = "warn",
+ msg =
+ "Used to enable ranger file browser (optional)\nNOTE: checkhealth won't detect this correctly, but you can ensure it is installed with 'pip list | grep pynvim'.",
+ },
+ {
+ cmd = { "ranger" },
+ type = "warn",
+ msg = "Used to enable ranger file browser (Optional)",
+ },
+ {
+ cmd = { "delta" },
+ type = "warn",
+ msg = "Used by undotree to show a diff (Optional)",
+ },
+ {
+ cmd = { "grcov" },
+ type = "warn",
+ msg = "Used to show code coverage (Optional)",
+ },
+ {
+ cmd = { "grcov" },
+ type = "warn",
+ msg = "Used to show code coverage (Optional)",
+ },
+ {
+ cmd = { "jest" },
+ type = "warn",
+ msg = "Used to run typescript and javascript tests (Optional)",
+ },
+ {
+ cmd = { "pytest" },
+ type = "warn",
+ msg = "Used to run python tests (Optional)",
+ },
+ {
+ cmd = { "cargo nextest" },
+ type = "warn",
+ msg =
+ "Used to run rust tests (optional)\nNOTE: checkhealth won't detect this correctly, but you can confirm it works correctly with 'cargo nextest'.",
+ },
+ {
+ cmd = { "nunit" },
+ type = "warn",
+ msg =
+ "Used to run C# tests (optional)\nNOTE: There is no way to install this system wide. To use it you must add it to your dotnet C# project: 'dotnet add package NUnit NUnit3TestAdapter'.",
+ },
+ {
+ cmd = { "csc" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile non dotnet C# files (Optional)",
+ },
+ {
+ cmd = { "mono" },
+ type = "warn",
+ msg = "Used by compiler.nvim to run non dotnet C# files. (Optional)",
+ },
+ {
+ cmd = { "dotnet" },
+ type = "warn",
+ msg =
+ "Used by compiler.nvim and DAP to operate with dotnet projects (optional)\nNOTE: Make sure you also have the system package dotnet-sdk installed.",
+ },
+ {
+ cmd = { "java" },
+ type = "warn",
+ msg = "Used by compiler.nvim and dap to operate with java (Optional)",
+ },
+ {
+ cmd = { "javac" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile java (Optional)",
+ },
+ {
+ cmd = { "nasm" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile assembly x86_64 (Optional)",
+ },
+
+ {
+ cmd = { "gcc" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile C (Optional)",
+ },
+ {
+ cmd = { "g++" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile C++ (Optional)",
+ },
+ {
+ cmd = { "elixir" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile elixir (optional)",
+ },
+ {
+ cmd = { "Rscript" },
+ type = "warn",
+ msg = "Used by compiler.nvim to interpretate R (Optional)",
+ },
+ {
+ cmd = { "python" },
+ type = "warn",
+ msg = "Used by compiler.nvim to interpretate python (Optional)",
+ },
+ {
+ cmd = { "nuitka3" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile python to machine code (Optional)",
+ },
+ {
+ cmd = { "pyinstaller" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile python to bytecode (Optional)",
+ },
+ {
+ cmd = { "ruby" },
+ type = "warn",
+ msg = "Used by compiler.nvim to interpretate ruby (optional)",
+ },
+ {
+ cmd = { "perl" },
+ type = "warn",
+ msg = "Used by compiler.nvim to interpretate perl (optional)",
+ },
+ {
+ cmd = { "swiftc" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile swift (optional)",
+ },
+ {
+ cmd = { "swift" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile swift (optional)",
+ },
+ {
+ cmd = { "gfortran" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile fortran (optional)"
+ },
+ {
+ cmd = { "fpm" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile fortran (optional)"
+ },
+ {
+ cmd = { "go" },
+ type = "warn",
+ msg = "Used by compiler.nvim to compile go (optional)",
+ },
+ {
+ cmd = { "godoc" },
+ type = "warn",
+ msg =
+ "Used by dooku.nvim to generate go html docs\nNOTE: If you have it installed but you can't run it on the terminal, ensure you have added 'go' to your OS path (optional)",
+ },
+ {
+ cmd = { "doxygen" },
+ type = "warn",
+ msg = "Used by dooku.nvim to generate c/c++/python/java html docs (optional)",
+ },
+ }
+
+ -- Actually perform the checks we defined above.
+ for _, program in ipairs(programs) do
+ if type(program.cmd) == "string" then program.cmd = { program.cmd } end
+ local name = table.concat(program.cmd, "/")
+ local found = false
+ for _, cmd in ipairs(program.cmd) do
+ if vim.fn.executable(cmd) == 1 then
+ name = cmd
+ found = true
+ break
+ end
+ end
+
+ if found then
+ health.ok(("`%s` is installed: %s"):format(name, program.msg))
+ else
+ health[program.type](
+ ("`%s` is not installed: %s"):format(name, program.msg)
+ )
+ end
+ end
+ health.info("")
+ health.info("Write `:bw` to close `:checkhealth` gracefully.")
+end
+
+return M
@@ -0,0 +1,73 @@
+-- ### Nerd fonts
+
+-- DESCRIPTION:
+-- Here you can edit the icons displayed in NormalNvim.
+
+-- If you can't see the default icons:
+-- Install nerd fonts and set it as your terminal font:
+-- https://www.nerdfonts.com/
+
+return {
+ ActiveLSP = "",
+ ActiveTS = "",
+ ArrowLeft = "",
+ ArrowRight = "",
+ Bookmarks = "",
+ BufferClose = "",
+ DapBreakpoint = "",
+ DapBreakpointCondition = "",
+ DapBreakpointRejected = "",
+ DapLogPoint = ".>",
+ DapStopped = "",
+ Debugger = "",
+ DefaultFile = "",
+ Diagnostic = "",
+ DiagnosticError = "",
+ DiagnosticHint = "",
+ DiagnosticInfo = "",
+ DiagnosticWarn = "",
+ Ellipsis = "…",
+ Environment = "",
+ FileNew = "",
+ FileModified = "",
+ FileReadOnly = "",
+ FoldClosed = "",
+ FoldOpened = "",
+ FoldSeparator = " ",
+ FolderClosed = "",
+ FolderEmpty = "",
+ FolderOpen = "",
+ Git = "",
+ GitAdd = "",
+ GitBranch = "",
+ GitChange = "",
+ GitConflict = "",
+ GitDelete = "",
+ GitIgnored = "◌",
+ GitRenamed = "➜",
+ GitSign = "▎",
+ GitStaged = "✓",
+ GitUnstaged = "✗",
+ GitUntracked = "★",
+ LSPLoaded = "",
+ LSPLoading1 = "",
+ LSPLoading2 = "",
+ LSPLoading3 = "",
+ MacroRecording = "",
+ Package = "",
+ Paste = "",
+ Refresh = "",
+ Run = "",
+ Search = "",
+ Selected = "❯",
+ Session = "",
+ Sort = "",
+ Spellcheck = "",
+ Tab = "",
+ TabClose = "",
+ Terminal = "",
+ Window = "",
+ WordFile = "",
+ Test = "",
+ Docs = "",
+}
@@ -0,0 +1,48 @@
+-- ### Text fonts
+
+-- DESCRIPTION:
+-- Fallback icons that will be displayed
+-- if you don't have nerd fonts installed,
+-- or if you set `vim.g.icons_enabled = false` on `../1-options.lua`.
+
+return {
+ ActiveLSP = "LSP:",
+ ArrowLeft = "<",
+ ArrowRight = ">",
+ BufferClose = "x",
+ DapBreakpoint = "B",
+ DapBreakpointCondition = "C",
+ DapBreakpointRejected = "R",
+ DapLogPoint = "L",
+ DapStopped = ">",
+ DefaultFile = "[F]",
+ DiagnosticError = "X",
+ DiagnosticHint = "?",
+ DiagnosticInfo = "i",
+ DiagnosticWarn = "!",
+ Ellipsis = "...",
+ Environment = "Env:",
+ FileModified = "*",
+ FileReadOnly = "[lock]",
+ FoldClosed = "+",
+ FoldOpened = "-",
+ FoldSeparator = " ",
+ FolderClosed = "[D]",
+ FolderEmpty = "[E]",
+ FolderOpen = "[O]",
+ GitAdd = "[+]",
+ GitChange = "[/]",
+ GitConflict = "[!]",
+ GitDelete = "[-]",
+ GitIgnored = "[I]",
+ GitRenamed = "[R]",
+ GitStaged = "[S]",
+ GitUnstaged = "[U]",
+ GitUntracked = "[?]",
+ MacroRecording = "Recording:",
+ Paste = "[PASTE]",
+ Search = "?",
+ Selected = "*",
+ Spellcheck = "[SPELL]",
+ TabClose = "X",
+}
@@ -0,0 +1,307 @@
+--- ### General utils.
+--
+-- DESCRIPTION:
+-- General utility functions to use within Nvim.
+
+-- Functions:
+-- -> run_cmd → Run a shell command and return true/false.
+-- -> add_autocmds_to_buffer → Add autocmds to a bufnr.
+-- -> del_autocmds_from_buffer → Delete autocmds from a bufnr.
+-- -> get_icon → Return an icon from the icons directory.
+-- -> get_mappings_template → Return a empty mappings table.
+-- -> is_available → Return true if the plugin exist.
+-- -> is_big_file → Return true if the file is too big.
+-- -> notify → Send a notification with a default title.
+-- -> os_path → Converts a path to the current OS.
+-- -> get_plugin_opts → Return a plugin opts table.
+-- -> set_mappings → Set a list of mappings in a clean way.
+-- -> set_url_effect → Show an effect for urls.
+-- -> open_with_program → Open the file or URL under the cursor.
+-- -> trigger_event → Manually trigger a event.
+-- -> which_key_register → When setting a mapping, add it to whichkey.
+
+
+local M = {}
+
+--- Run a shell command and capture the output and if the command
+--- succeeded or failed.
+---@param cmd string|string[] The terminal command to execute
+---@param show_error? boolean If true, print errors if the command fail.
+---@return string|nil # The result of a successfully executed command or nil
+function M.run_cmd(cmd, show_error)
+ if type(cmd) == "string" then cmd = vim.split(cmd, " ") end
+ if vim.fn.has "win32" == 1 then cmd = vim.list_extend({ "cmd.exe", "/C" }, cmd) end
+ local result = vim.fn.system(cmd)
+ local success = vim.api.nvim_get_vvar "shell_error" == 0
+ if not success and (show_error == nil or show_error) then
+ vim.api.nvim_err_writeln(("Error running command %s\nError message:\n%s"):format(table.concat(cmd, " "), result))
+ end
+ return success and result:gsub("[\27\155][][()#;?%d]*[A-PRZcf-ntqry=><~]", "") or nil
+end
+
+--- Adds autocmds to a specific buffer if they don't already exist.
+---
+--- @param augroup string The name of the autocmd group to which the autocmds belong.
+--- @param bufnr number The buffer number to which the autocmds should be applied.
+--- @param autocmds table|any A table or a single autocmd definition containing the autocmds to add.
+function M.add_autocmds_to_buffer(augroup, bufnr, autocmds)
+ -- Check if autocmds is a list, if not convert it to a list
+ if not vim.islist(autocmds) then autocmds = { autocmds } end
+
+ -- Attempt to retrieve existing autocmds associated with the specified augroup and bufnr
+ local cmds_found, cmds = pcall(vim.api.nvim_get_autocmds, { group = augroup, buffer = bufnr })
+
+ -- If no existing autocmds are found or the cmds_found call fails
+ if not cmds_found or vim.tbl_isempty(cmds) then
+ -- Create a new augroup if it doesn't already exist
+ vim.api.nvim_create_augroup(augroup, { clear = false })
+
+ -- Iterate over each autocmd provided
+ for _, autocmd in ipairs(autocmds) do
+ -- Extract the events from the autocmd and remove the events key
+ local events = autocmd.events
+ autocmd.events = nil
+
+ -- Set the group and buffer keys for the autocmd
+ autocmd.group = augroup
+ autocmd.buffer = bufnr
+
+ -- Create the autocmd
+ vim.api.nvim_create_autocmd(events, autocmd)
+ end
+ end
+end
+
+--- Deletes autocmds associated with a specific buffer and autocmd group.
+---
+--- @param augroup string The name of the autocmd group from which the autocmds should be removed.
+--- @param bufnr number The buffer number from which the autocmds should be removed.
+function M.del_autocmds_from_buffer(augroup, bufnr)
+ -- Attempt to retrieve existing autocmds associated with the specified augroup and bufnr
+ local cmds_found, cmds = pcall(vim.api.nvim_get_autocmds, { group = augroup, buffer = bufnr })
+
+ -- If retrieval was successful
+ if cmds_found then
+ -- Map over each retrieved autocmd and delete it
+ vim.tbl_map(function(cmd) vim.api.nvim_del_autocmd(cmd.id) end, cmds)
+ end
+end
+
+--- Get an icon from `lspkind` if it is available and return it.
+---@param kind string The kind of icon in `lspkind` to retrieve.
+---@return string icon.
+function M.get_icon(kind, padding, no_fallback)
+ if not vim.g.icons_enabled and no_fallback then return "" end
+ local icon_pack = vim.g.icons_enabled and "icons" or "text_icons"
+ if not M[icon_pack] then
+ M.icons = require("base.icons.nerd_font")
+ M.text_icons = require("base.icons.text")
+ end
+ local icon = M[icon_pack] and M[icon_pack][kind]
+ return icon and icon .. string.rep(" ", padding or 0) or ""
+end
+
+--- Get an empty table of mappings with a key for each map mode.
+---@return table<string,table> # a table with entries for each map mode.
+function M.get_mappings_template()
+ local maps = {}
+ for _, mode in ipairs { "", "n", "v", "x", "s", "o", "!", "i", "l", "c", "t" } do
+ maps[mode] = {}
+ end
+ if vim.fn.has "nvim-0.10.0" == 1 then
+ for _, abbr_mode in ipairs { "ia", "ca", "!a" } do
+ maps[abbr_mode] = {}
+ end
+ end
+ return maps
+end
+
+--- Check if a plugin is defined in lazy. Useful with lazy loading
+--- when a plugin is not necessarily loaded yet.
+---@param plugin string The plugin to search for.
+---@return boolean available # Whether the plugin is available.
+function M.is_available(plugin)
+ local lazy_config_avail, lazy_config = pcall(require, "lazy.core.config")
+ return lazy_config_avail and lazy_config.spec.plugins[plugin] ~= nil
+end
+
+--- Returns true if the file is considered a big file,
+--- according to the criteria defined in `vim.g.big_file`.
+---@param bufnr number|nil buffer number. 0 by default, which means current buf.
+---@return boolean is_big_file true or false.
+function M.is_big_file(bufnr)
+ if bufnr == nil then bufnr = 0 end
+ local filesize = vim.fn.getfsize(vim.api.nvim_buf_get_name(bufnr))
+ local nlines = vim.api.nvim_buf_line_count(bufnr)
+ local is_big_file = (filesize > vim.g.big_file.size)
+ or (nlines > vim.g.big_file.lines)
+ return is_big_file
+end
+
+--- Sends a notification with 'Neovim' as default title.
+--- Same as using vim.notify, but it saves us typing the title every time.
+---@param msg string The notification body.
+---@param type number|nil The type of the notification (:help vim.log.levels).
+---@param opts? table The nvim-notify options to use (:help notify-options).
+function M.notify(msg, type, opts)
+ vim.schedule(function()
+ vim.notify(
+ msg, type, vim.tbl_deep_extend("force", { title = "Neovim" }, opts or {}))
+ end)
+end
+
+--- Convert a path to the path format of the current operative system.
+--- It converts 'slash' to 'inverted slash' if on windows, and vice versa on UNIX.
+---@param path string A path string.
+---@return string|nil,nil path A path string formatted for the current OS.
+function M.os_path(path)
+ if path == nil then return nil end
+ -- Get the platform-specific path separator
+ local separator = string.sub(package.config, 1, 1)
+ return string.gsub(path, '[/\\]', separator)
+end
+
+--- Get the options of a plugin managed by lazy.
+---@param plugin string The plugin to get options from
+---@return table opts # The plugin options, or empty table if no plugin.
+function M.get_plugin_opts(plugin)
+ local lazy_config_avail, lazy_config = pcall(require, "lazy.core.config")
+ local lazy_plugin_avail, lazy_plugin = pcall(require, "lazy.core.plugin")
+ local opts = {}
+ if lazy_config_avail and lazy_plugin_avail then
+ local spec = lazy_config.spec.plugins[plugin]
+ if spec then opts = lazy_plugin.values(spec, "opts") end
+ end
+ return opts
+end
+
+--- Set a table of mappings.
+---
+--- This wrapper prevents a boilerplate code, and takes care of `whichkey.nvim`.
+---@param map_table table A nested table where the first key is the vim mode,
+--- the second key is the key to map, and the value is
+--- the function to set the mapping to.
+---@param base? table A base set of options to set on every keybinding.
+function M.set_mappings(map_table, base)
+ -- iterate over the first keys for each mode
+ base = base or {}
+ for mode, maps in pairs(map_table) do
+ -- iterate over each keybinding set in the current mode
+ for keymap, options in pairs(maps) do
+ -- build the options for the command accordingly
+ if options then
+ local cmd = options
+ local keymap_opts = base
+ if type(options) == "table" then
+ cmd = options[1]
+ keymap_opts = vim.tbl_deep_extend("force", keymap_opts, options)
+ keymap_opts[1] = nil
+ end
+ if not cmd or keymap_opts.name then -- if which-key mapping, queue it
+ if not keymap_opts.name then keymap_opts.name = keymap_opts.desc end
+ if not M.which_key_queue then M.which_key_queue = {} end
+ if not M.which_key_queue[mode] then M.which_key_queue[mode] = {} end
+ M.which_key_queue[mode][keymap] = keymap_opts
+ else -- if not which-key mapping, set it
+ vim.keymap.set(mode, keymap, cmd, keymap_opts)
+ end
+ end
+ end
+ end
+ -- if which-key is loaded already, register
+ if package.loaded["which-key"] then M.which_key_register() end
+end
+
+--- Add syntax matching rules for highlighting URLs/URIs.
+function M.set_url_effect()
+ --- regex used for matching a valid URL/URI string
+ local url_matcher =
+ "\\v\\c%(%(h?ttps?|ftp|file|ssh|git)://|[a-z]+[@][a-z]+[.][a-z]+:)" ..
+ "%([&:#*@~%_\\-=?!+;/0-9a-z]+%(%([.;/?]|[.][.]+)" ..
+ "[&:#*@~%_\\-=?!+/0-9a-z]+|:\\d+|,%(%(%(h?ttps?|ftp|file|ssh|git)://|" ..
+ "[a-z]+[@][a-z]+[.][a-z]+:)@![0-9a-z]+))*|\\([&:#*@~%_\\-=?!+;/.0-9a-z]*\\)" ..
+ "|\\[[&:#*@~%_\\-=?!+;/.0-9a-z]*\\]|\\{%([&:#*@~%_\\-=?!+;/.0-9a-z]*" ..
+ "|\\{[&:#*@~%_\\-=?!+;/.0-9a-z]*})\\})+"
+
+ M.delete_url_effect()
+ if vim.g.url_effect_enabled then
+ vim.fn.matchadd("HighlightURL", url_matcher, 15)
+ end
+end
+
+--- Delete the syntax matching rules for URLs/URIs if set.
+function M.delete_url_effect()
+ for _, match in ipairs(vim.fn.getmatches()) do
+ if match.group == "HighlightURL" then vim.fn.matchdelete(match.id) end
+ end
+end
+
+--- Open the file or url under the cursor.
+---@param path string The path of the file to open with the system opener.
+function M.open_with_program(path)
+ if vim.ui.open then return vim.ui.open(path) end
+ local cmd
+ if vim.fn.has "mac" == 1 then
+ cmd = { "open" }
+ elseif vim.fn.has "win32" == 1 then
+ if vim.fn.executable "rundll32" then
+ cmd = { "rundll32", "url.dll,FileProtocolHandler" }
+ else
+ cmd = { "cmd.exe", "/K", "explorer" }
+ end
+ elseif vim.fn.has "unix" == 1 then
+ if vim.fn.executable "explorer.exe" == 1 then -- available in WSL
+ cmd = { "explorer.exe" }
+ elseif vim.fn.executable "xdg-open" == 1 then
+ cmd = { "xdg-open" }
+ end
+ end
+ if not cmd then M.notify("Available system opening tool not found!", vim.log.levels.ERROR) end
+ if not path then
+ path = vim.fn.expand "<cfile>"
+ elseif not path:match "%w+:" then
+ path = vim.fn.expand(path)
+ end
+ vim.fn.jobstart(vim.list_extend(cmd, { path }), { detach = true })
+end
+
+--- Convenient wapper to save code when we Trigger events.
+--- To listen for a event triggered by this function you can use `autocmd`.
+---@param event string Name of the event.
+---@param is_urgent boolean|nil If true, trigger directly instead of scheduling. Useful for startup events.
+-- @usage To run a User event: `trigger_event("User MyUserEvent")`
+-- @usage To run a Neovim event: `trigger_event("BufEnter")
+function M.trigger_event(event, is_urgent)
+ -- define behavior
+ local function trigger()
+ local is_user_event = string.match(event, "^User ") ~= nil
+ if is_user_event then
+ event = event:gsub("^User ", "")
+ vim.api.nvim_exec_autocmds("User", { pattern = event, modeline = false })
+ else
+ vim.api.nvim_exec_autocmds(event, { modeline = false })
+ end
+ end
+
+ -- execute
+ if is_urgent then
+ trigger()
+ else
+ vim.schedule(trigger)
+ end
+end
+
+--- Register queued which-key mappings.
+function M.which_key_register()
+ if M.which_key_queue then
+ local wk_avail, wk = pcall(require, "which-key")
+ if wk_avail then
+ for mode, registration in pairs(M.which_key_queue) do
+ wk.register(registration, { mode = mode })
+ end
+ M.which_key_queue = nil
+ end
+ end
+end
+
+return M
@@ -0,0 +1,189 @@
+--- ### LSP utils.
+--
+-- DESCRIPTION:
+-- Functions we use to configure the plugin `mason-lspconfig.nvim`.
+-- You can specify your own lsp settings inside `M.apply_user_lsp_settings()`.
+--
+-- Most options we use in `M.apply_default_lsp_settings()`
+-- can be tweaked on the file `../1-options.lua`.
+-- Take this into consideration to minimize the risk of breaking stuff.
+
+-- Functions:
+-- -> M.apply_default_lsp_settings → Apply our default lsp settings.
+-- -> M.apply_user_lsp_mappings → Apply the user lsp keymappings.
+-- -> M.apply_user_lsp_settings → Apply the user lsp settings.
+-- -> M.setup → It passes the user lsp settings to lspconfig.
+
+local M = {}
+local utils = require "base.utils"
+local stored_handlers = {}
+
+--- Apply default settings for diagnostics, formatting, and lsp capabilities.
+--- It only need to be executed once, normally on mason-lspconfig.
+---@return nil
+M.apply_default_lsp_settings = function()
+ -- Icons
+ -- Apply the icons defined in ../icons/nerd_font.lua
+ local get_icon = utils.get_icon
+ local signs = {
+ { name = "DiagnosticSignError", text = get_icon("DiagnosticError"), texthl = "DiagnosticSignError" },
+ { name = "DiagnosticSignWarn", text = get_icon("DiagnosticWarn"), texthl = "DiagnosticSignWarn" },
+ { name = "DiagnosticSignHint", text = get_icon("DiagnosticHint"), texthl = "DiagnosticSignHint" },
+ { name = "DiagnosticSignInfo", text = get_icon("DiagnosticInfo"), texthl = "DiagnosticSignInfo" },
+ { name = "DapStopped", text = get_icon("DapStopped"), texthl = "DiagnosticWarn" },
+ { name = "DapBreakpoint", text = get_icon("DapBreakpoint"), texthl = "DiagnosticInfo" },
+ { name = "DapBreakpointRejected", text = get_icon("DapBreakpointRejected"), texthl = "DiagnosticError" },
+ { name = "DapBreakpointCondition", text = get_icon("DapBreakpointCondition"), texthl = "DiagnosticInfo" },
+ { name = "DapLogPoint", text = get_icon("DapLogPoint"), texthl = "DiagnosticInfo" }
+ }
+ for _, sign in ipairs(signs) do
+ vim.fn.sign_define(sign.name, sign)
+ end
+
+ -- Borders
+ -- Apply the option lsp_round_borders_enabled from ../1-options.lua
+ if vim.g.lsp_round_borders_enabled then
+ vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded", silent = true })
+ vim.lsp.handlers["textDocument/signatureHelp"] =
+ vim.lsp.with(vim.lsp.handlers.signature_help, { border = "rounded", silent = true })
+ end
+
+ -- Set default diagnostics
+ local default_diagnostics = {
+ virtual_text = true,
+ signs = {
+ text = {
+ [vim.diagnostic.severity.ERROR] = utils.get_icon("DiagnosticError"),
+ [vim.diagnostic.severity.HINT] = utils.get_icon("DiagnosticHint"),
+ [vim.diagnostic.severity.WARN] = utils.get_icon("DiagnosticWarn"),
+ [vim.diagnostic.severity.INFO] = utils.get_icon("DiagnosticInfo"),
+ },
+ active = signs,
+ },
+ update_in_insert = true,
+ underline = true,
+ severity_sort = true,
+ float = {
+ focused = false,
+ style = "minimal",
+ border = "rounded",
+ source = "always",
+ header = "",
+ prefix = "",
+ },
+ }
+
+ -- Apply default diagnostics
+ -- Applies the option diagnostics_mode from ../1-options.lua
+ M.diagnostics = {
+ -- diagnostics off
+ [0] = vim.tbl_deep_extend(
+ "force",
+ default_diagnostics,
+ { underline = false, virtual_text = false, signs = false, update_in_insert = false }
+ ),
+ -- status only
+ vim.tbl_deep_extend("force", default_diagnostics, { virtual_text = false, signs = false }),
+ -- virtual text off, signs on
+ vim.tbl_deep_extend("force", default_diagnostics, { virtual_text = false }),
+ -- all diagnostics on
+ default_diagnostics,
+ }
+ vim.diagnostic.config(M.diagnostics[vim.g.diagnostics_mode])
+
+ -- Apply formatting settings
+ M.formatting = { format_on_save = { enabled = true }, disabled = {} }
+ if type(M.formatting.format_on_save) == "boolean" then
+ M.formatting.format_on_save = { enabled = M.formatting.format_on_save }
+ end
+ M.format_opts = vim.deepcopy(M.formatting)
+ M.format_opts.disabled = nil
+ M.format_opts.format_on_save = nil
+ M.format_opts.filter = function(client)
+ local filter = M.formatting.filter
+ local disabled = M.formatting.disabled or {}
+ -- check if client is fully disabled or filtered by function
+ return not (vim.tbl_contains(disabled, client.name) or (type(filter) == "function" and not filter(client)))
+ end
+end
+
+--- This function has the sole purpose of passing the lsp keymappings to lsp.
+--- We have this function, because we use it on none-ls.
+---@param client string The client where the lsp mappings will load.
+---@param bufnr string The bufnr where the lsp mappings will load.
+function M.apply_user_lsp_mappings(client, bufnr)
+ local lsp_mappings = require("base.4-mappings").lsp_mappings(client, bufnr)
+ if not vim.tbl_isempty(lsp_mappings.v) then
+ lsp_mappings.v["<leader>l"] = { desc = utils.get_icon("ActiveLSP", 1, true) .. "LSP" }
+ end
+ utils.set_mappings(lsp_mappings, { buffer = bufnr })
+end
+
+--- Here you can specify custom settings for the lsp servers you install.
+--- This is not normally necessary. But you can.
+---@param server_name string The name of the server
+---@return table # The table of LSP options used when setting up the given language server
+function M.apply_user_lsp_settings(server_name)
+ local server = require("lspconfig")[server_name]
+
+ -- Define user server capabilities.
+ M.capabilities = vim.lsp.protocol.make_client_capabilities()
+ M.capabilities.textDocument.completion.completionItem.documentationFormat = { "markdown", "plaintext" }
+ M.capabilities.textDocument.completion.completionItem.snippetSupport = true
+ M.capabilities.textDocument.completion.completionItem.preselectSupport = true
+ M.capabilities.textDocument.completion.completionItem.insertReplaceSupport = true
+ M.capabilities.textDocument.completion.completionItem.labelDetailsSupport = true
+ M.capabilities.textDocument.completion.completionItem.deprecatedSupport = true
+ M.capabilities.textDocument.completion.completionItem.commitCharactersSupport = true
+ M.capabilities.textDocument.completion.completionItem.tagSupport = { valueSet = { 1 } }
+ M.capabilities.textDocument.completion.completionItem.resolveSupport =
+ { properties = { "documentation", "detail", "additionalTextEdits" } }
+ M.capabilities.textDocument.foldingRange = { dynamicRegistration = false, lineFoldingOnly = true }
+ M.flags = {}
+ local opts = vim.tbl_deep_extend("force", server, { capabilities = M.capabilities, flags = M.flags })
+
+ -- Define user server rules.
+ if server_name == "jsonls" then -- Add schemastore schemas
+ local is_schemastore_loaded, schemastore = pcall(require, "schemastore")
+ if is_schemastore_loaded then
+ opts.settings = { json = { schemas = schemastore.json.schemas(), validate = { enable = true } } }
+ end
+ end
+ if server_name == "yamlls" then -- Add schemastore schemas
+ local is_schemastore_loaded, schemastore = pcall(require, "schemastore")
+ if is_schemastore_loaded then opts.settings = { yaml = { schemas = schemastore.yaml.schemas() } } end
+ end
+ if server_name == "lua_ls" then -- Disable third party checking
+ pcall(require, "neodev")
+ opts.settings = { Lua = { workspace = { checkThirdParty = false } } }
+ end
+
+ -- Apply them
+ local old_on_attach = server.on_attach
+ opts.on_attach = function(client, bufnr)
+ -- If the server on_attach function exist → server.on_attach(client, bufnr)
+ if type(old_on_attach) == "function" then old_on_attach(client, bufnr) end
+ -- Also, apply mappings to the buffer.
+ M.apply_user_lsp_mappings(client, bufnr)
+ end
+ return opts
+end
+
+--- This function passes the `user lsp settings` to lspconfig,
+--- which is the responsible of configuring everything for us.
+---
+--- You are meant to call this function from the plugin `mason-lspconfig.nvim`.
+---@param server string A lsp server name.
+---@return nil
+M.setup = function(server)
+ -- Get the user settings.
+ local opts = M.apply_user_lsp_settings(server)
+
+ -- Get a handler from lspconfig.
+ local setup_handler = stored_handlers[server] or require("lspconfig")[server].setup(opts)
+
+ -- Apply our user settings to the lspconfig handler.
+ if setup_handler then setup_handler(server, opts) end
+end
+
+return M
@@ -0,0 +1,321 @@
+--- ### UI toggle functions.
+--
+-- DESCRIPTION:
+-- While you could technically delete this file, we encourage you
+-- to keep it as it takes a lot of complexity out of `../4-mappings.lua`.
+
+-- Functions:
+-- -> change_number
+-- -> set_indent
+-- -> toggle_animations
+-- -> toggle_autoformat
+-- -> toggle_autopairs
+-- -> toggle_background
+-- -> toggle_buffer_autoformat
+-- -> toggle_buffer_inlay_hints
+-- -> toggle_buffer_semantic_tokens
+-- -> toggle_buffer_syntax
+-- -> toggle_codelens
+-- -> toggle_coverage_signs
+-- -> toggle_cmp
+-- -> toggle_conceal
+-- -> toggle_diagnostics
+-- -> toggle_foldcolumn
+-- -> toggle_inlay_hints
+-- -> toggle_lsp_signature
+-- -> toggle_paste
+-- -> toggle_signcolumn
+-- -> toggle_spell
+-- -> toggle_statusline
+-- -> toggle_tabline
+-- -> toggle_ui_notifications
+-- -> toggle_url_effect
+-- -> toggle_wrap
+-- -> toggle_zen_mode
+
+
+local M = {}
+local utils = require("base.utils")
+local function bool2str(bool) return bool and "on" or "off" end
+
+--- Change the number display modes
+function M.change_number()
+ local number = vim.wo.number -- local to window
+ local relativenumber = vim.wo.relativenumber -- local to window
+ if not number and not relativenumber then
+ vim.wo.number = true
+ elseif number and not relativenumber then
+ vim.wo.relativenumber = true
+ elseif number and relativenumber then
+ vim.wo.number = false
+ else -- not number and relativenumber
+ vim.wo.relativenumber = false
+ end
+ utils.notify(string.format("number %s, relativenumber %s", bool2str(vim.wo.number), bool2str(vim.wo.relativenumber)))
+end
+
+--- Set the indent and tab related numbers
+function M.set_indent()
+ local input_avail, input = pcall(vim.fn.input, "Set indent value (>0 expandtab, <=0 noexpandtab): ")
+ if input_avail then
+ local indent = tonumber(input)
+ if not indent or indent == 0 then return end
+ vim.bo.expandtab = (indent > 0) -- local to buffer
+ indent = math.abs(indent)
+ vim.bo.tabstop = indent -- local to buffer
+ vim.bo.softtabstop = indent -- local to buffer
+ vim.bo.shiftwidth = indent -- local to buffer
+ utils.notify(string.format("indent=%d %s", indent, vim.bo.expandtab and "expandtab" or "noexpandtab"))
+ end
+end
+
+--- Toggle animations
+function M.toggle_animations()
+ if vim.g.minianimate_disable then
+ vim.g.minianimate_disable = false
+ else
+ vim.g.minianimate_disable = true
+ end
+
+ local state = vim.g.minianimate_disable
+ utils.notify(string.format("animations %s", bool2str(not state)))
+end
+
+--- Toggle auto format
+function M.toggle_autoformat()
+ vim.g.autoformat_enabled = not vim.g.autoformat_enabled
+ utils.notify(string.format("Global autoformatting %s", bool2str(vim.g.autoformat_enabled)))
+end
+
+--- Toggle autopairs
+function M.toggle_autopairs()
+ local ok, autopairs = pcall(require, "nvim-autopairs")
+ if ok then
+ if autopairs.state.disabled then
+ autopairs.enable()
+ else
+ autopairs.disable()
+ end
+ vim.g.autopairs_enabled = autopairs.state.disabled
+ utils.notify(string.format("autopairs %s", bool2str(not autopairs.state.disabled)))
+ else
+ utils.notify "autopairs not available"
+ end
+end
+
+--- Toggle background="dark"|"light"
+function M.toggle_background()
+ vim.go.background = vim.go.background == "light" and "dark" or "light"
+ utils.notify(string.format("background=%s", vim.go.background))
+end
+
+--- Toggle buffer local auto format
+function M.toggle_buffer_autoformat(bufnr)
+ bufnr = bufnr or 0
+ local old_val = vim.b[bufnr].autoformat_enabled
+ if old_val == nil then old_val = vim.g.autoformat_enabled end
+ vim.b[bufnr].autoformat_enabled = not old_val
+ utils.notify(string.format("Buffer autoformatting %s", bool2str(vim.b[bufnr].autoformat_enabled)))
+end
+
+--- Toggle LSP inlay hints (buffer)
+-- @param bufnr? number the buffer to toggle the clients on
+function M.toggle_buffer_inlay_hints(bufnr)
+ bufnr = bufnr or 0
+ vim.b[bufnr].inlay_hints_enabled = not vim.b[bufnr].inlay_hints_enabled
+ vim.lsp.inlay_hint.enable(vim.b[bufnr].inlay_hints_enabled, { bufnr = bufnr })
+ utils.notify(string.format("Buffer inlay hints %s", bool2str(vim.b[bufnr].inlay_hints_enabled)))
+end
+
+--- Toggle buffer semantic token highlighting for all language servers that support it
+--@param bufnr? number the buffer to toggle the clients on
+function M.toggle_buffer_semantic_tokens(bufnr)
+ bufnr = bufnr or 0
+ vim.b[bufnr].semantic_tokens_enabled = not vim.b[bufnr].semantic_tokens_enabled
+ for _, client in ipairs(vim.lsp.get_clients({ bufnr = bufnr })) do
+ if client.server_capabilities.semanticTokensProvider then
+ vim.lsp.semantic_tokens[vim.b[bufnr].semantic_tokens_enabled and "start" or "stop"](bufnr, client.id)
+ utils.notify(string.format("Buffer lsp semantic highlighting %s", bool2str(vim.b[bufnr].semantic_tokens_enabled)))
+ end
+ end
+end
+
+--- Toggle syntax highlighting and treesitter
+function M.toggle_buffer_syntax(bufnr)
+ -- HACK: this should just be `bufnr = bufnr or 0` but it looks like
+ -- `vim.treesitter.stop` has a bug with `0` being current.
+ bufnr = (bufnr and bufnr ~= 0) and bufnr or vim.api.nvim_win_get_buf(0)
+ local ts_avail, parsers = pcall(require, "nvim-treesitter.parsers")
+ if vim.bo[bufnr].syntax == "off" then
+ if ts_avail and parsers.has_parser() then vim.treesitter.start(bufnr) end
+ vim.bo[bufnr].syntax = "on"
+ if not vim.b.semantic_tokens_enabled then M.toggle_buffer_semantic_tokens(bufnr, true) end
+ else
+ if ts_avail and parsers.has_parser() then vim.treesitter.stop(bufnr) end
+ vim.bo[bufnr].syntax = "off"
+ if vim.b.semantic_tokens_enabled then M.toggle_buffer_semantic_tokens(bufnr, true) end
+ end
+ utils.notify(string.format("syntax %s", bool2str(vim.bo[bufnr].syntax)))
+end
+
+--- Toggle codelens
+function M.toggle_codelens(bufnr)
+ bufnr = bufnr or 0
+ vim.g.codelens_enabled = not vim.g.codelens_enabled
+ if vim.g.codelens_enabled then
+ vim.lsp.codelens.refresh({ bufnr = bufnr })
+ else
+ vim.lsp.codelens.clear()
+ end
+ utils.notify(string.format("CodeLens %s", bool2str(vim.g.codelens_enabled)))
+end
+
+--- Toggle coverage signs
+function M.toggle_coverage_signs(bufnr)
+ bufnr = bufnr or 0
+ vim.b[bufnr].coverage_signs_enabled = not vim.b[bufnr].coverage_signs_enabled
+ if vim.b[bufnr].coverage_signs_enabled then
+ utils.notify("Coverage signs on:" ..
+ "\n\n- Git signs will be temporary disabled." ..
+ "\n- Diagnostic signs won't be automatically disabled.")
+ vim.cmd("Gitsigns toggle_signs")
+ require("coverage").load(true)
+ else
+ utils.notify("Coverage signs off:\n\n- Git signs re-enabled.")
+ require("coverage").hide()
+ vim.cmd("Gitsigns toggle_signs")
+ end
+end
+
+--- Toggle cmp entrirely
+function M.toggle_cmp()
+ vim.g.cmp_enabled = not vim.g.cmp_enabled
+ local ok, _ = pcall(require, "cmp")
+ utils.notify(ok and string.format("completion %s", bool2str(vim.g.cmp_enabled)) or "completion not available")
+end
+
+--- Toggle conceal=2|0
+function M.toggle_conceal()
+ vim.opt.conceallevel = vim.opt.conceallevel:get() == 0 and 2 or 0
+ utils.notify(string.format("conceal %s", bool2str(vim.opt.conceallevel:get() == 2)))
+end
+
+--- Toggle diagnostics
+function M.toggle_diagnostics()
+ vim.g.diagnostics_mode = (vim.g.diagnostics_mode - 1) % 4
+ vim.diagnostic.config(require("base.utils.lsp").diagnostics[vim.g.diagnostics_mode])
+ if vim.g.diagnostics_mode == 0 then
+ utils.notify "diagnostics off"
+ elseif vim.g.diagnostics_mode == 1 then
+ utils.notify "only status diagnostics"
+ elseif vim.g.diagnostics_mode == 2 then
+ utils.notify "virtual text off"
+ else
+ utils.notify "all diagnostics on"
+ end
+end
+
+local last_active_foldcolumn
+--- Toggle foldcolumn=0|1
+function M.toggle_foldcolumn()
+ local curr_foldcolumn = vim.wo.foldcolumn
+ if curr_foldcolumn ~= "0" then last_active_foldcolumn = curr_foldcolumn end
+ vim.wo.foldcolumn = curr_foldcolumn == "0" and (last_active_foldcolumn or "1") or "0"
+ utils.notify(string.format("foldcolumn=%s", vim.wo.foldcolumn))
+end
+
+--- Toggle LSP inlay hints (global)
+-- @param bufnr? number the buffer to toggle the clients on
+function M.toggle_inlay_hints(bufnr)
+ bufnr = bufnr or 0
+ vim.g.inlay_hints_enabled = not vim.g.inlay_hints_enabled -- flip global state
+ vim.b.inlay_hints_enabled = not vim.g.inlay_hints_enabled -- sync buffer state
+ vim.lsp.buf.inlay_hint.enable(vim.g.inlay_hints_enabled, { bufnr = bufnr }) -- apply state
+ utils.notify(string.format("Global inlay hints %s", bool2str(vim.g.inlay_hints_enabled)))
+end
+
+--- Toggle lsp signature
+function M.toggle_lsp_signature()
+ local state = require('lsp_signature').toggle_float_win()
+ utils.notify(string.format("lsp signature %s", bool2str(state)))
+end
+
+--- Toggle paste
+function M.toggle_paste()
+ vim.opt.paste = not vim.opt.paste:get() -- local to window
+ utils.notify(string.format("paste %s", bool2str(vim.opt.paste:get())))
+end
+
+--- Toggle signcolumn="auto"|"no"
+function M.toggle_signcolumn()
+ if vim.wo.signcolumn == "no" then
+ vim.wo.signcolumn = "yes"
+ elseif vim.wo.signcolumn == "yes" then
+ vim.wo.signcolumn = "auto"
+ else
+ vim.wo.signcolumn = "no"
+ end
+ utils.notify(string.format("signcolumn=%s", vim.wo.signcolumn))
+end
+
+--- Toggle spell
+function M.toggle_spell()
+ vim.wo.spell = not vim.wo.spell -- local to window
+ utils.notify(string.format("spell %s", bool2str(vim.wo.spell)))
+end
+
+--- Toggle laststatus=3|2|0
+function M.toggle_statusline()
+ local laststatus = vim.opt.laststatus:get()
+ local status
+ if laststatus == 0 then
+ vim.opt.laststatus = 2
+ status = "local"
+ elseif laststatus == 2 then
+ vim.opt.laststatus = 3
+ status = "global"
+ elseif laststatus == 3 then
+ vim.opt.laststatus = 0
+ status = "off"
+ end
+ utils.notify(string.format("statusline %s", status))
+end
+
+--- Toggle showtabline=2|0
+function M.toggle_tabline()
+ vim.opt.showtabline = vim.opt.showtabline:get() == 0 and 2 or 0
+ utils.notify(string.format("tabline %s", bool2str(vim.opt.showtabline:get() == 2)))
+end
+
+--- Toggle notifications for UI toggles
+function M.toggle_ui_notifications()
+ vim.g.notifications_enabled = not vim.g.notifications_enabled
+ utils.notify(string.format("Notifications %s", bool2str(vim.g.notifications_enabled)))
+end
+
+--- Toggle URL/URI syntax highlighting rules
+function M.toggle_url_effect()
+ vim.g.url_effect_enabled = not vim.g.url_effect_enabled
+ require("base.utils").set_url_effect()
+ utils.notify(string.format("URL effect %s", bool2str(vim.g.url_effect_enabled)))
+end
+
+--- Toggle wrap
+function M.toggle_wrap()
+ vim.wo.wrap = not vim.wo.wrap -- local to window
+ utils.notify(string.format("wrap %s", bool2str(vim.wo.wrap)))
+end
+
+--- Toggle zen mode
+function M.toggle_zen_mode(bufnr)
+ bufnr = bufnr or 0
+ if not vim.b[bufnr].zen_mode then
+ vim.b[bufnr].zen_mode = true
+ else
+ vim.b[bufnr].zen_mode = false
+ end
+ utils.notify(string.format("zen mode %s", bool2str(vim.b[bufnr].zen_mode)))
+ vim.cmd "ZenMode"
+end
+
+return M
@@ -0,0 +1,709 @@
+-- Core behaviors
+-- Things that add new behaviors.
+
+-- Sections:
+-- -> ranger file browser [ranger]
+-- -> project.nvim [project search + auto cd]
+-- -> trim.nvim [auto trim spaces]
+-- -> stickybuf.nvim [lock special buffers]
+-- -> mini.bufremove [smart bufdelete]
+-- -> smart-splits [move and resize buffers]
+-- -> better-scape.nvim [esc]
+-- -> toggleterm.nvim [term]
+-- -> session-manager [session]
+-- -> spectre.nvim [search and replace in project]
+-- -> neotree file browser [neotree]
+-- -> nvim-ufo [folding mod]
+-- -> nvim-neoclip [nvim clipboard]
+-- -> zen-mode.nvim [distraction free mode]
+-- -> suda.vim [write as sudo]
+-- -> vim-matchup [Improved % motion]
+-- -> hop.nvim [go to word visually]
+-- -> nvim-autopairs [auto close brackets]
+-- -> lsp_signature.nvim [auto params help]
+-- -> nvim-lightbulb [lightbulb for code actions]
+-- -> distroupdate.nvim [distro update]
+
+local is_windows = vim.fn.has('win32') == 1 -- true if on windows
+local is_android = vim.fn.isdirectory('/data') == 1 -- true if on android
+
+return {
+ -- [ranger] file browser
+ -- https://github.com/kevinhwang91/rnvimr
+ -- This is NormalNvim file browser, which is only for Linux.
+ --
+ -- If you are on Windows, you have 3 options:
+ -- * Use neotree instead (<space>+e).
+ -- * Delete rnvimr and install some other file browser you like.
+ -- * Or enable WLS on Windows and launch neovim from there.
+ -- This way you can install and use 'ranger' and its dependency 'pynvim'.
+ {
+ "kevinhwang91/rnvimr",
+ event = "User BaseDefered",
+ cmd = { "RnvimrToggle" },
+ enabled = not is_windows,
+ config = function()
+ -- vim.g.rnvimr_vanilla = 1 -- Often solves issues in your ranger config.
+ vim.g.rnvimr_enable_picker = 1 -- Close rnvimr after choosing a file.
+ vim.g.rnvimr_ranger_cmd = { "ranger" } -- By passing a script like TERM=foot ranger "$@" you can open terminals inside ranger.
+ if is_android then -- Open on full screenn
+ vim.g.rnvimr_layout = {
+ relative = "editor",
+ width = 200,
+ height = 100,
+ col = 0,
+ row = 0,
+ style = "minimal",
+ }
+ end
+ end,
+ },
+
+ -- project.nvim [project search + auto cd]
+ -- https://github.com/ahmedkhalf/project.nvim
+ {
+ "zeioth/project.nvim",
+ event = "User BaseDefered",
+ cmd = "ProjectRoot",
+ opts = {
+ -- How to find root directory
+ patterns = {
+ ".git",
+ "_darcs",
+ ".hg",
+ ".bzr",
+ ".svn",
+ "Makefile",
+ "package.json",
+ ".solution",
+ ".solution.toml"
+ },
+ -- Don't list the next projects
+ exclude_dirs = {
+ "~/"
+ },
+ silent_chdir = true,
+ manual_mode = false,
+
+ -- Don't chdir for certain buffers
+ exclude_chdir = {
+ filetype = {"", "OverseerList", "alpha"},
+ buftype = {"nofile", "terminal"},
+ },
+
+ --ignore_lsp = { "lua_ls" },
+ },
+ config = function(_, opts) require("project_nvim").setup(opts) end,
+ },
+
+ -- trim.nvim [auto trim spaces]
+ -- https://github.com/cappyzawa/trim.nvim
+ {
+ "cappyzawa/trim.nvim",
+ event = "BufWrite",
+ opts = {
+ trim_on_write = true,
+ trim_trailing = true,
+ trim_last_line = false,
+ trim_first_line = false,
+ -- ft_blocklist = { "markdown", "text", "org", "tex", "asciidoc", "rst" },
+ -- patterns = {[[%s/\(\n\n\)\n\+/\1/]]}, -- Only one consecutive bl
+ },
+ },
+
+ -- stickybuf.nvim [lock special buffers]
+ -- https://github.com/arnamak/stay-centered.nvim
+ -- By default it support neovim/aerial and others.
+ {
+ "stevearc/stickybuf.nvim",
+ event = "User BaseDefered",
+ config = function() require("stickybuf").setup() end
+ },
+
+ -- mini.bufremove [smart bufdelete]
+ -- https://github.com/echasnovski/mini.bufremove
+ -- Defines what tab to go on :bufdelete
+ {
+ "echasnovski/mini.bufremove",
+ event = "User BaseFile"
+ },
+
+ -- smart-splits [move and resize buffers]
+ -- https://github.com/mrjones2014/smart-splits.nvim
+ {
+ "mrjones2014/smart-splits.nvim",
+ event = "User BaseFile",
+ opts = {
+ ignored_filetypes = { "nofile", "quickfix", "qf", "prompt" },
+ ignored_buftypes = { "nofile" },
+ },
+ },
+
+ -- better-scape.nvim [esc]
+ -- https://github.com/max397574/better-escape.nvim
+ {
+ "max397574/better-escape.nvim",
+ event = "InsertCharPre",
+ opts = {
+ mapping = {},
+ timeout = 300,
+ },
+ },
+
+ -- Toggle floating terminal on <F7> [term]
+ -- https://github.com/akinsho/toggleterm.nvim
+ -- neovim bug → https://github.com/neovim/neovim/issues/21106
+ -- workarounds → https://github.com/akinsho/toggleterm.nvim/wiki/Mouse-support
+ {
+ "akinsho/toggleterm.nvim",
+ cmd = { "ToggleTerm", "TermExec" },
+ opts = {
+ highlights = {
+ Normal = { link = "Normal" },
+ NormalNC = { link = "NormalNC" },
+ NormalFloat = { link = "Normal" },
+ FloatBorder = { link = "FloatBorder" },
+ StatusLine = { link = "StatusLine" },
+ StatusLineNC = { link = "StatusLineNC" },
+ WinBar = { link = "WinBar" },
+ WinBarNC = { link = "WinBarNC" },
+ },
+ size = 10,
+ open_mapping = [[<F7>]],
+ shading_factor = 2,
+ direction = "float",
+ float_opts = {
+ border = "rounded",
+ highlights = { border = "Normal", background = "Normal" },
+ },
+ },
+ },
+
+ -- session-manager [session]
+ -- https://github.com/Shatur/neovim-session-manager
+ {
+ "Shatur/neovim-session-manager",
+ event = "User BaseDefered",
+ cmd = "SessionManager",
+ opts = function()
+ local config = require('session_manager.config')
+ return {
+ autoload_mode = config.AutoloadMode.Disabled,
+ autosave_last_session = false,
+ autosave_only_in_session = false,
+ }
+ end,
+ config = function(_, opts)
+ local session_manager = require('session_manager')
+ session_manager.setup(opts)
+
+ -- Auto save session
+ -- BUG: This feature will auto-close anything nofile before saving.
+ -- This include neotree, aerial, mergetool, among others.
+ -- Consider commenting the next block if this is important for you.
+ --
+ -- This won't be necessary once neovim fixes:
+ -- https://github.com/neovim/neovim/issues/12242
+ -- vim.api.nvim_create_autocmd({ 'BufWritePre' }, {
+ -- callback = function ()
+ -- session_manager.save_current_session()
+ -- end
+ -- })
+ end
+ },
+
+ -- spectre.nvim [search and replace in project]
+ -- https://github.com/nvim-pack/nvim-spectre
+ -- INSTRUCTIONS:
+ -- To see the instructions press '?'
+ -- To start the search press <ESC>.
+ -- It doesn't have ctrl-z so please always commit before using it.
+ {
+ "nvim-pack/nvim-spectre",
+ cmd = "Spectre",
+ opts = {
+ default = {
+ find = {
+ -- pick one of item in find_engine [ fd, rg ]
+ cmd = "fd",
+ options = {}
+ },
+ replace = {
+ -- pick one of item in [ sed, oxi ]
+ cmd = "sed"
+ },
+ },
+ is_insert_mode = true, -- start open panel on is_insert_mode
+ is_block_ui_break = true, -- prevent the UI from breaking
+ mapping = {
+ ["toggle_line"] = {
+ map = "d",
+ cmd = "<cmd>lua require('spectre').toggle_line()<CR>",
+ desc = "toggle item.",
+ },
+ ["enter_file"] = {
+ map = "<cr>",
+ cmd = "<cmd>lua require('spectre.actions').select_entry()<CR>",
+ desc = "open file.",
+ },
+ ["send_to_qf"] = {
+ map = "sqf",
+ cmd = "<cmd>lua require('spectre.actions').send_to_qf()<CR>",
+ desc = "send all items to quickfix.",
+ },
+ ["replace_cmd"] = {
+ map = "src",
+ cmd = "<cmd>lua require('spectre.actions').replace_cmd()<CR>",
+ desc = "replace command.",
+ },
+ ["show_option_menu"] = {
+ map = "so",
+ cmd = "<cmd>lua require('spectre').show_options()<CR>",
+ desc = "show options.",
+ },
+ ["run_current_replace"] = {
+ map = "c",
+ cmd = "<cmd>lua require('spectre.actions').run_current_replace()<CR>",
+ desc = "confirm item.",
+ },
+ ["run_replace"] = {
+ map = "R",
+ cmd = "<cmd>lua require('spectre.actions').run_replace()<CR>",
+ desc = "replace all.",
+ },
+ ["change_view_mode"] = {
+ map = "sv",
+ cmd = "<cmd>lua require('spectre').change_view()<CR>",
+ desc = "results view mode.",
+ },
+ ["change_replace_sed"] = {
+ map = "srs",
+ cmd = "<cmd>lua require('spectre').change_engine_replace('sed')<CR>",
+ desc = "use sed to replace.",
+ },
+ ["change_replace_oxi"] = {
+ map = "sro",
+ cmd = "<cmd>lua require('spectre').change_engine_replace('oxi')<CR>",
+ desc = "use oxi to replace.",
+ },
+ ["toggle_live_update"] = {
+ map = "sar",
+ cmd = "<cmd>lua require('spectre').toggle_live_update()<CR>",
+ desc = "auto refresh changes when nvim writes a file.",
+ },
+ ["resume_last_search"] = {
+ map = "sl",
+ cmd = "<cmd>lua require('spectre').resume_last_search()<CR>",
+ desc = "repeat last search.",
+ },
+ ["insert_qwerty"] = {
+ map = "i",
+ cmd = "<cmd>startinsert<CR>",
+ desc = "insert (qwerty).",
+ },
+ ["insert_colemak"] = {
+ map = "o",
+ cmd = "<cmd>startinsert<CR>",
+ desc = "insert (colemak).",
+ },
+ ["quit"] = {
+ map = "q",
+ cmd = "<cmd>lua require('spectre').close()<CR>",
+ desc = "quit.",
+ },
+ },
+ },
+ },
+
+ -- [neotree]
+ -- https://github.com/nvim-neo-tree/neo-tree.nvim
+ {
+ "nvim-neo-tree/neo-tree.nvim",
+ dependencies = "MunifTanjim/nui.nvim",
+ cmd = "Neotree",
+ opts = function()
+ vim.g.neo_tree_remove_legacy_commands = true
+ local utils = require("base.utils")
+ local get_icon = utils.get_icon
+ return {
+ auto_clean_after_session_restore = true,
+ close_if_last_window = true,
+ buffers = {
+ show_unloaded = true
+ },
+ sources = { "filesystem", "buffers", "git_status" },
+ source_selector = {
+ winbar = true,
+ content_layout = "center",
+ sources = {
+ {
+ source = "filesystem",
+ display_name = get_icon("FolderClosed", 1, true) .. "File",
+ },
+ {
+ source = "buffers",
+ display_name = get_icon("DefaultFile", 1, true) .. "Bufs",
+ },
+ {
+ source = "git_status",
+ display_name = get_icon("Git", 1, true) .. "Git",
+ },
+ {
+ source = "diagnostics",
+ display_name = get_icon("Diagnostic", 1, true) .. "Diagnostic",
+ },
+ },
+ },
+ default_component_configs = {
+ indent = { padding = 0 },
+ icon = {
+ folder_closed = get_icon("FolderClosed"),
+ folder_open = get_icon("FolderOpen"),
+ folder_empty = get_icon("FolderEmpty"),
+ folder_empty_open = get_icon("FolderEmpty"),
+ default = get_icon "DefaultFile",
+ },
+ modified = { symbol = get_icon "FileModified" },
+ git_status = {
+ symbols = {
+ added = get_icon("GitAdd"),
+ deleted = get_icon("GitDelete"),
+ modified = get_icon("GitChange"),
+ renamed = get_icon("GitRenamed"),
+ untracked = get_icon("GitUntracked"),
+ ignored = get_icon("GitIgnored"),
+ unstaged = get_icon("GitUnstaged"),
+ staged = get_icon("GitStaged"),
+ conflict = get_icon("GitConflict"),
+ },
+ },
+ },
+ -- A command is a function that we can assign to a mapping (below)
+ commands = {
+ system_open = function(state)
+ require("base.utils").open_with_program(state.tree:get_node():get_id())
+ end,
+ parent_or_close = function(state)
+ local node = state.tree:get_node()
+ if
+ (node.type == "directory" or node:has_children())
+ and node:is_expanded()
+ then
+ state.commands.toggle_node(state)
+ else
+ require("neo-tree.ui.renderer").focus_node(
+ state,
+ node:get_parent_id()
+ )
+ end
+ end,
+ child_or_open = function(state)
+ local node = state.tree:get_node()
+ if node.type == "directory" or node:has_children() then
+ if not node:is_expanded() then -- if unexpanded, expand
+ state.commands.toggle_node(state)
+ else -- if expanded and has children, seleect the next child
+ require("neo-tree.ui.renderer").focus_node(
+ state,
+ node:get_child_ids()[1]
+ )
+ end
+ else -- if not a directory just open it
+ state.commands.open(state)
+ end
+ end,
+ copy_selector = function(state)
+ local node = state.tree:get_node()
+ local filepath = node:get_id()
+ local filename = node.name
+ local modify = vim.fn.fnamemodify
+
+ local results = {
+ e = { val = modify(filename, ":e"), msg = "Extension only" },
+ f = { val = filename, msg = "Filename" },
+ F = {
+ val = modify(filename, ":r"),
+ msg = "Filename w/o extension",
+ },
+ h = {
+ val = modify(filepath, ":~"),
+ msg = "Path relative to Home",
+ },
+ p = {
+ val = modify(filepath, ":."),
+ msg = "Path relative to CWD",
+ },
+ P = { val = filepath, msg = "Absolute path" },
+ }
+
+ local messages = {
+ { "\nChoose to copy to clipboard:\n", "Normal" },
+ }
+ for i, result in pairs(results) do
+ if result.val and result.val ~= "" then
+ vim.list_extend(messages, {
+ { ("%s."):format(i), "Identifier" },
+ { (" %s: "):format(result.msg) },
+ { result.val, "String" },
+ { "\n" },
+ })
+ end
+ end
+ vim.api.nvim_echo(messages, false, {})
+ local result = results[vim.fn.getcharstr()]
+ if result and result.val and result.val ~= "" then
+ vim.notify("Copied: " .. result.val)
+ vim.fn.setreg("+", result.val)
+ end
+ end,
+ find_in_dir = function(state)
+ local node = state.tree:get_node()
+ local path = node:get_id()
+ require("telescope.builtin").find_files {
+ cwd = node.type == "directory" and path
+ or vim.fn.fnamemodify(path, ":h"),
+ }
+ end,
+ },
+ window = {
+ width = 30,
+ mappings = {
+ ["<space>"] = false, -- disable space until we figure out which-key disabling
+ ["<S-CR>"] = "system_open",
+ ["[b"] = "prev_source",
+ ["]b"] = "next_source",
+ F = utils.is_available "telescope.nvim" and "find_in_dir" or nil,
+ O = "system_open",
+ Y = "copy_selector",
+ h = "parent_or_close",
+ l = "child_or_open",
+ },
+ },
+ filesystem = {
+ follow_current_file = {
+ enabled = true,
+ },
+ hijack_netrw_behavior = "open_current",
+ use_libuv_file_watcher = true,
+ },
+ event_handlers = {
+ {
+ event = "neo_tree_buffer_enter",
+ handler = function(_) vim.opt_local.signcolumn = "auto" end,
+ },
+ },
+ }
+ end,
+ },
+
+ -- code [folding mod] + [promise-asyn] dependency
+ -- https://github.com/kevinhwang91/nvim-ufo
+ -- https://github.com/kevinhwang91/promise-async
+ {
+ "kevinhwang91/nvim-ufo",
+ event = { "User BaseFile" },
+ dependencies = { "kevinhwang91/promise-async" },
+ opts = {
+ preview = {
+ mappings = {
+ scrollB = "<C-b>",
+ scrollF = "<C-f>",
+ scrollU = "<C-u>",
+ scrollD = "<C-d>",
+ },
+ },
+ provider_selector = function(_, filetype, buftype)
+ local function handleFallbackException(bufnr, err, providerName)
+ if type(err) == "string" and err:match "UfoFallbackException" then
+ return require("ufo").getFolds(bufnr, providerName)
+ else
+ return require("promise").reject(err)
+ end
+ end
+
+ -- only use indent until a file is opened
+ return (filetype == "" or buftype == "nofile") and "indent"
+ or function(bufnr)
+ return require("ufo")
+ .getFolds(bufnr, "lsp")
+ :catch(
+ function(err)
+ return handleFallbackException(bufnr, err, "treesitter")
+ end
+ )
+ :catch(
+ function(err)
+ return handleFallbackException(bufnr, err, "indent")
+ end
+ )
+ end
+ end,
+ },
+ },
+
+ -- nvim-neoclip [nvim clipboard]
+ -- https://github.com/AckslD/nvim-neoclip.lua
+ -- Read their docs to enable cross-session history.
+ {
+ "AckslD/nvim-neoclip.lua",
+ requires = 'nvim-telescope/telescope.nvim',
+ event = "User BaseFile",
+ opts = {}
+ },
+
+ -- zen-mode.nvim [distraction free mode]
+ -- https://github.com/folke/zen-mode.nvim
+ {
+ "folke/zen-mode.nvim",
+ cmd = "ZenMode",
+ },
+
+ -- suda.nvim [write as sudo]
+ -- https://github.com/lambdalisue/suda.vim
+ {
+ "lambdalisue/suda.vim",
+ cmd = { "SudaRead", "SudaWrite" },
+ },
+
+ -- vim-matchup [improved % motion]
+ -- https://github.com/andymass/vim-matchup
+ {
+ "andymass/vim-matchup",
+ event = "User BaseFile",
+ config = function()
+ vim.g.matchup_matchparen_deferred = 1 -- work async
+ vim.g.matchup_matchparen_offscreen = {} -- disable status bar icon
+ end,
+ },
+
+ -- hop.nvim [go to word visually]
+ -- https://github.com/smoka7/hop.nvim
+ {
+ "smoka7/hop.nvim",
+ cmd = { "HopWord" },
+ opts = { keys = "etovxqpdygfblzhckisuran" }
+ },
+
+ -- nvim-autopairs [auto close brackets]
+ -- https://github.com/windwp/nvim-autopairs
+ -- It's disabled by default, you can enable it with <space>ua
+ {
+ "windwp/nvim-autopairs",
+ event = "InsertEnter",
+ opts = {
+ check_ts = true,
+ ts_config = { java = false },
+ fast_wrap = {
+ map = "<M-e>",
+ chars = { "{", "[", "(", '"', "'" },
+ pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], "%s+", ""),
+ offset = 0,
+ end_key = "$",
+ keys = "qwertyuiopzxcvbnmasdfghjkl",
+ check_comma = true,
+ highlight = "PmenuSel",
+ highlight_grey = "LineNr",
+ },
+ },
+ config = function(_, opts)
+ local npairs = require("nvim-autopairs")
+ npairs.setup(opts)
+ if not vim.g.autopairs_enabled then npairs.disable() end
+
+ local is_cmp_loaded, cmp = pcall(require, "cmp")
+ if is_cmp_loaded then
+ cmp.event:on(
+ "confirm_done",
+ require("nvim-autopairs.completion.cmp").on_confirm_done {
+ tex = false }
+ )
+ end
+ end
+ },
+
+ -- lsp_signature.nvim [auto params help]
+ -- https://github.com/ray-x/lsp_signature.nvim
+ {
+ "ray-x/lsp_signature.nvim",
+ event = "User BaseFile",
+ opts = function()
+ -- Apply globals from 1-options.lua
+ local is_enabled = vim.g.lsp_signature_enabled
+ local round_borders = {}
+ if vim.g.lsp_round_borders_enabled then
+ round_borders = { border = 'rounded' }
+ end
+ return {
+ -- Window mode
+ floating_window = is_enabled, -- Display it as floating window.
+ hi_parameter = "IncSearch", -- Color to highlight floating window.
+ handler_opts = round_borders, -- Window style
+
+ -- Hint mode
+ hint_enable = false, -- Display it as hint.
+ hint_prefix = "👈 ",
+
+ -- Additionally, you can use <space>uH to toggle inlay hints.
+ toggle_key_flip_floatwin_setting = is_enabled
+ }
+ end,
+ config = function(_, opts) require('lsp_signature').setup(opts) end
+ },
+
+ -- nvim-lightbulb [lightbulb for code actions]
+ -- https://github.com/kosayoda/nvim-lightbulb
+ -- Show a lightbulb where a code action is available
+ {
+ 'kosayoda/nvim-lightbulb',
+ enabled = vim.g.codeactions_enabled,
+ event = "User BaseFile",
+ opts = {
+ action_kinds = { -- show only for relevant code actions.
+ "quickfix",
+ },
+ ignore = {
+ ft = { "lua" }, -- ignore filetypes with bad code actions.
+ },
+ autocmd = {
+ enabled = true,
+ updatetime = 100,
+ },
+ sign = { enabled = false },
+ virtual_text = {
+ enabled = true,
+ text = "💡"
+ }
+ },
+ config = function(_, opts) require("nvim-lightbulb").setup(opts) end
+ },
+
+ -- distroupdate.nvim [distro update]
+ -- https://github.com/zeioth/distroupdate.nvim
+ {
+ "zeioth/distroupdate.nvim",
+ dependencies = { "nvim-lua/plenary.nvim" },
+ cmd = {
+ "DistroFreezePluginVersions",
+ "DistroReadChangelog",
+ "DistroReadVersion",
+ "DistroUpdate",
+ "DistroUpdateRevert"
+ },
+ opts = function()
+ local utils = require("base.utils")
+ local config_dir = utils.os_path(vim.fn.stdpath "config" .. "/lua/base/")
+ return {
+ channel = "stable", -- stable/nightly
+ hot_reload_files = {
+ config_dir .. "1-options.lua",
+ config_dir .. "4-mappings.lua"
+ },
+ hot_reload_callback = function()
+ vim.cmd(":silent! colorscheme " .. base.default_colorscheme) -- nvim colorscheme reload command
+ vim.cmd(":silent! doautocmd ColorScheme") -- heirline colorscheme reload event
+ end
+ }
+ end
+ },
+
+} -- end of return
@@ -0,0 +1,709 @@
+-- User interface
+-- Things that make the GUI better.
+
+-- Sections:
+-- -> tokyonight [theme]
+-- -> astrotheme [theme]
+-- -> alpha-nvim [greeter]
+-- -> nvim-notify [notifications]
+-- -> mini.indentscope [guides]
+-- -> heirline-components.nvim [ui components]
+-- -> heirline [ui components]
+-- -> telescope [search]
+-- -> telescope-fzf-native.nvim [search backend]
+-- -> smart-splits [window-dimming]
+-- -> dressing.nvim [better ui elements]
+-- -> noice.nvim [better cmd/search line]
+-- -> nvim-web-devicons [icons | ui]
+-- -> lspkind.nvim [icons | lsp]
+-- -> nvim-scrollbar [scrollbar]
+-- -> mini.animate [animations]
+-- -> highlight-undo [highlights]
+-- -> which-key [on-screen keybinding]
+
+local utils = require "base.utils"
+local is_windows = vim.fn.has('win32') == 1 -- true if on windows
+local is_android = vim.fn.isdirectory('/data') == 1 -- true if on android
+
+return {
+
+ -- tokyonight [theme]
+ -- https://github.com/folke/tokyonight.nvim
+ {
+ "zeioth/tokyonight.nvim",
+ event = "User LoadColorSchemes",
+ opts = {
+ dim_inactive = false,
+ styles = {
+ comments = { italic = true },
+ keywords = { italic = true },
+ },
+ }
+ },
+
+ -- astrotheme [theme]
+ -- https://github.com/AstroNvim/astrotheme
+ {
+ "AstroNvim/astrotheme",
+ event = "User LoadColorSchemes",
+ opts = {
+ palette = "astrodark",
+ plugins = { ["dashboard-nvim"] = true },
+ },
+ },
+
+ -- alpha-nvim [greeter]
+ -- https://github.com/goolord/alpha-nvim
+ {
+ "goolord/alpha-nvim",
+ cmd = "Alpha",
+ -- setup header and buttonts
+ opts = function()
+ local dashboard = require("alpha.themes.dashboard")
+
+ -- Header
+ -- dashboard.section.header.val = {
+ -- " ",
+ -- " ████ ██████ █████ ██ ",
+ -- " ███████████ █████ ",
+ -- " █████████ ███████████████████ ███ ███████████ ",
+ -- " █████████ ███ █████████████ █████ ██████████████ ",
+ -- " █████████ ██████████ █████████ █████ █████ ████ █████ ",
+ -- " ███████████ ███ ███ █████████ █████ █████ ████ █████ ",
+ -- " ██████ █████████████████████ ████ █████ █████ ████ ██████ ",
+ -- }
+ -- dashboard.section.header.val = {
+ -- ' ▟▙ ',
+ -- ' ▝▘ ',
+ -- '██▃▅▇█▆▖ ▗▟████▙▖ ▄████▄ ██▄ ▄██ ██ ▗▟█▆▄▄▆█▙▖',
+ -- '██▛▔ ▝██ ██▄▄▄▄██ ██▛▔▔▜██ ▝██ ██▘ ██ ██▛▜██▛▜██',
+ -- '██ ██ ██▀▀▀▀▀▘ ██▖ ▗██ ▜█▙▟█▛ ██ ██ ██ ██',
+ -- '██ ██ ▜█▙▄▄▄▟▊ ▀██▙▟██▀ ▝████▘ ██ ██ ██ ██',
+ -- '▀▀ ▀▀ ▝▀▀▀▀▀ ▀▀▀▀ ▀▀ ▀▀ ▀▀ ▀▀ ▀▀',
+ -- }
+ -- dashboard.section.header.val = {
+ -- ' ▟▙ ',
+ -- ' ▝▘ ',
+ -- '██▃▅▇█▆▖ ██▄ ▄██ ██ ▗▟█▆▄▄▆█▙▖',
+ -- '██▛▔ ▝██ ▝██ ██▘ ██ ██▛▜██▛▜██',
+ -- '██ ██ ▜█▙▟█▛ ██ ██ ██ ██',
+ -- '██ ██ ▝████▘ ██ ██ ██ ██',
+ -- '▀▀ ▀▀ ▀▀ ▀▀ ▀▀ ▀▀ ▀▀',
+ -- }
+ -- Generated with https://www.fancytextpro.com/BigTextGenerator/Larry3D
+ -- dashboard.section.header.val = {
+ -- [[ __ __ __ __ ]],
+ -- [[/\ \/\ \ /\ \/\ \ __ ]],
+ -- [[\ \ `\\ \ __ ___ \ \ \ \ \/\_\ ___ ___ ]],
+ -- [[ \ \ , ` \ /'__`\ / __`\\ \ \ \ \/\ \ /' __` __`\ ]],
+ -- [[ \ \ \`\ \/\ __//\ \L\ \\ \ \_/ \ \ \/\ \/\ \/\ \ ]],
+ -- [[ \ \_\ \_\ \____\ \____/ \ `\___/\ \_\ \_\ \_\ \_\]],
+ -- [[ \/_/\/_/\/____/\/___/ `\/__/ \/_/\/_/\/_/\/_/]],
+ -- }
+ -- dashboard.section.header.val = {
+ -- ' ',
+ -- ' ███╗ ██╗███████╗ ██████╗ ██╗ ██╗██╗███╗ ███╗ ',
+ -- ' ████╗ ██║██╔════╝██╔═══██╗██║ ██║██║████╗ ████║ ',
+ -- ' ██╔██╗ ██║█████╗ ██║ ██║██║ ██║██║██╔████╔██║ ',
+ -- ' ██║╚██╗██║██╔══╝ ██║ ██║╚██╗ ██╔╝██║██║╚██╔╝██║ ',
+ -- ' ██║ ╚████║███████╗╚██████╔╝ ╚████╔╝ ██║██║ ╚═╝ ██║ ',
+ -- ' ╚═╝ ╚═══╝╚══════╝ ╚═════╝ ╚═══╝ ╚═╝╚═╝ ╚═╝ ',
+ -- ' ',
+ -- }
+ -- dashboard.section.header.val = {
+ -- [[ __ ]],
+ -- [[ ___ __ __ /\_\ ___ ___ ]],
+ -- [[/' _ `\/\ \/\ \\/\ \ /' __` __`\ ]],
+ -- [[/\ \/\ \ \ \_/ |\ \ \/\ \/\ \/\ \ ]],
+ -- [[\ \_\ \_\ \___/ \ \_\ \_\ \_\ \_\]],
+ -- [[ \/_/\/_/\/__/ \/_/\/_/\/_/\/_/]],
+ -- }
+
+ if is_android then
+ dashboard.section.header.val = {
+ [[ __ ]],
+ [[ __ __ /\_\ ___ ___ ]],
+ [[/\ \/\ \\/\ \ /' __` __`\ ]],
+ [[\ \ \_/ |\ \ \/\ \/\ \/\ \ ]],
+ [[ \ \___/ \ \_\ \_\ \_\ \_\]],
+ [[ \/__/ \/_/\/_/\/_/\/_/]],
+ }
+ else
+ dashboard.section.header.val = {
+ [[888b 88 88]],
+ [[8888b 88 88]],
+ [[88 `8b 88 88]],
+ [[88 `8b 88 ,adPPYba, 8b,dPPYba, 88,dPYba,,adPYba, ,adPPYYba, 88]],
+ [[88 `8b 88 a8" "8a 88P' "Y8 88P' "88" "8a "" `Y8 88]],
+ [[88 `8b 88 8b d8 88 88 88 88 ,adPPPPP88 88]],
+ [[88 `8888 "8a, ,a8" 88 88 88 88 88, ,88 88]],
+ [[88 `888 `"YbbdP"' 88 88 88 88 `"8bbdP"Y8 88]],
+ [[ __ ]],
+ [[ ___ __ __ /\_\ ___ ___ ]],
+ [[ /' _ `\/\ \/\ \\/\ \ /' __` __`\ ]],
+ [[ /\ \/\ \ \ \_/ |\ \ \/\ \/\ \/\ \ ]],
+ [[ \ \_\ \_\ \___/ \ \_\ \_\ \_\ \_\]],
+ [[ \/_/\/_/\/__/ \/_/\/_/\/_/\/_/]],
+ }
+ end
+
+ dashboard.section.header.opts.hl = "DashboardHeader"
+ vim.cmd "highlight DashboardHeader guifg=#F7778F"
+
+ -- If on windows, don't show the 'ranger' button
+ local ranger_button = dashboard.button("r", "🐍 Ranger ", "<cmd>RnvimrToggle<CR>")
+ if is_windows then ranger_button = nil end
+
+ -- Buttons
+ dashboard.section.buttons.val = {
+ dashboard.button("n", "📄 New ", "<cmd>ene<CR>"),
+ dashboard.button("e", "🌺 Recent ", "<cmd>Telescope oldfiles<CR>"),
+ ranger_button,
+ dashboard.button(
+ "s",
+ "🔎 Sessions",
+ "<cmd>SessionManager! load_session<CR>"
+ ),
+ dashboard.button("p", "💼 Projects", "<cmd>Telescope projects<CR>"),
+ dashboard.button("", ""),
+ dashboard.button("q", " Quit", "<cmd>exit<CR>"),
+ -- --button("LDR f '", " Bookmarks "),
+ }
+
+ -- Vertical margins
+ dashboard.config.layout[1].val =
+ vim.fn.max { 2, vim.fn.floor(vim.fn.winheight(0) * 0.10) } -- Above header
+ dashboard.config.layout[3].val =
+ vim.fn.max { 2, vim.fn.floor(vim.fn.winheight(0) * 0.10) } -- Above buttons
+
+ -- Disable autocmd and return
+ dashboard.config.opts.noautocmd = true
+ return dashboard
+ end,
+ config = function(_, opts)
+ -- Footer
+ require("alpha").setup(opts.config)
+ vim.api.nvim_create_autocmd("User", {
+ pattern = "LazyVimStarted",
+ desc = "Add Alpha dashboard footer",
+ once = true,
+ callback = function()
+ local stats = require("lazy").stats()
+ stats.real_cputime = not is_windows
+ local ms = math.floor(stats.startuptime * 100 + 0.5) / 100
+ opts.section.footer.val = {
+ " ",
+ " ",
+ " ",
+ "Loaded " .. stats.loaded .. " plugins in " .. ms .. "ms",
+ ".............................",
+ }
+ opts.section.footer.opts.hl = "DashboardFooter"
+ vim.cmd "highlight DashboardFooter guifg=#D29B68"
+ pcall(vim.cmd.AlphaRedraw)
+ end,
+ })
+ end,
+ },
+
+ -- [notifications]
+ -- https://github.com/rcarriga/nvim-notify
+ {
+ "rcarriga/nvim-notify",
+ event = "User BaseDefered",
+ opts = function()
+ local fps
+ if is_android then fps = 30 else fps = 144 end
+
+ return {
+ timeout = 2500,
+ fps = fps,
+ max_height = function() return math.floor(vim.o.lines * 0.75) end,
+ max_width = function() return math.floor(vim.o.columns * 0.75) end,
+ on_open = function(win)
+ -- enable markdown support on notifications
+ vim.api.nvim_win_set_config(win, { zindex = 175 })
+ if not vim.g.notifications_enabled then
+ vim.api.nvim_win_close(win, true)
+ end
+ if not package.loaded["nvim-treesitter"] then
+ pcall(require, "nvim-treesitter")
+ end
+ vim.wo[win].conceallevel = 3
+ local buf = vim.api.nvim_win_get_buf(win)
+ if not pcall(vim.treesitter.start, buf, "markdown") then
+ vim.bo[buf].syntax = "markdown"
+ end
+ vim.wo[win].spell = false
+ end,
+ }
+ end,
+ config = function(_, opts)
+ local notify = require("notify")
+ notify.setup(opts)
+ vim.notify = notify
+ end,
+ },
+
+ -- mini.indentscope [guides]
+ -- https://github.com/echasnovski/mini.indentscope
+ {
+ "echasnovski/mini.indentscope",
+ event = { "BufReadPre", "BufNewFile" },
+ opts = {
+ draw = { delay = 0, animation = function() return 0 end },
+ options = { border = "top", try_as_border = true },
+ symbol = "▏",
+ },
+ config = function(_, opts)
+ require("mini.indentscope").setup(opts)
+
+ -- Disable for certain filetypes
+ vim.api.nvim_create_autocmd({ "FileType" }, {
+ desc = "Disable indentscope for certain filetypes",
+ callback = function()
+ local ignored_filetypes = {
+ "aerial",
+ "dashboard",
+ "help",
+ "lazy",
+ "leetcode.nvim",
+ "mason",
+ "neo-tree",
+ "NvimTree",
+ "neogitstatus",
+ "notify",
+ "startify",
+ "toggleterm",
+ "Trouble",
+ "calltree",
+ "coverage"
+ }
+ if vim.tbl_contains(ignored_filetypes, vim.bo.filetype) then
+ vim.b.miniindentscope_disable = true
+ end
+ end,
+ })
+ end
+ },
+
+ -- heirline-components.nvim [ui components]
+ -- https://github.com/zeioth/heirline-components.nvim
+ -- Collection of components to use on your heirline config.
+ {
+ "zeioth/heirline-components.nvim",
+ opts = {
+ icons = require("base.icons.nerd_font")
+ }
+ },
+
+ -- heirline [ui components]
+ -- https://github.com/rebelot/heirline.nvim
+ -- Use it to customize the components of your user interface,
+ -- Including tabline, winbar, statuscolumn, statusline.
+ -- Be aware some components are positional. Read heirline documentation.
+ {
+ "rebelot/heirline.nvim",
+ dependencies = { "zeioth/heirline-components.nvim" },
+ event = "User BaseDefered",
+ opts = function()
+ local lib = require "heirline-components.all"
+ return {
+ opts = {
+ disable_winbar_cb = function(args) -- We do this to avoid showing it on the greeter.
+ local is_disabled = not require("heirline-components.buffer").is_valid(args.buf) or
+ lib.condition.buffer_matches({
+ buftype = { "terminal", "prompt", "nofile", "help", "quickfix" },
+ filetype = { "NvimTree", "neo%-tree", "dashboard", "Outline", "aerial" },
+ }, args.buf)
+ return is_disabled
+ end,
+ },
+ tabline = { -- UI upper bar
+ lib.component.tabline_conditional_padding(),
+ lib.component.tabline_buffers(),
+ lib.component.fill { hl = { bg = "tabline_bg" } },
+ lib.component.tabline_tabpages()
+ },
+ winbar = { -- UI breadcrumbs bar
+ init = function(self) self.bufnr = vim.api.nvim_get_current_buf() end,
+ fallthrough = false,
+ -- Winbar for terminal, neotree, and aerial.
+ {
+ condition = function() return not lib.condition.is_active() end,
+ {
+ lib.component.neotree(),
+ lib.component.compiler_play(),
+ lib.component.fill(),
+ lib.component.compiler_redo(),
+ lib.component.aerial(),
+ },
+ },
+ -- Regular winbar
+ {
+ lib.component.neotree(),
+ lib.component.compiler_play(),
+ lib.component.fill(),
+ lib.component.breadcrumbs(),
+ lib.component.fill(),
+ lib.component.compiler_redo(),
+ lib.component.aerial(),
+ }
+ },
+ statuscolumn = { -- UI left column
+ init = function(self) self.bufnr = vim.api.nvim_get_current_buf() end,
+ lib.component.foldcolumn(),
+ lib.component.numbercolumn(),
+ lib.component.signcolumn(),
+ } or nil,
+ statusline = { -- UI statusbar
+ hl = { fg = "fg", bg = "bg" },
+ lib.component.mode(),
+ lib.component.git_branch(),
+ lib.component.file_info(),
+ lib.component.git_diff(),
+ lib.component.diagnostics(),
+ lib.component.fill(),
+ lib.component.cmd_info(),
+ lib.component.fill(),
+ lib.component.lsp(),
+ lib.component.compiler_state(),
+ lib.component.virtual_env(),
+ lib.component.nav(),
+ lib.component.mode { surround = { separator = "right" } },
+ },
+ }
+ end,
+ config = function(_, opts)
+ local heirline = require("heirline")
+ local heirline_components = require "heirline-components.all"
+
+ -- Setup
+ heirline_components.init.subscribe_to_events()
+ heirline.load_colors(heirline_components.hl.get_colors())
+ heirline.setup(opts)
+ end,
+ },
+
+ -- Telescope [search] + [search backend] dependency
+ -- https://github.com/nvim-telescope/telescope.nvim
+ -- https://github.com/nvim-telescope/telescope-fzf-native.nvim
+ -- https://github.com/debugloop/telescope-undo.nvim
+ -- NOTE: Normally, plugins that depend on Telescope are defined separately.
+ -- But its Telescope extension is added in the Telescope 'config' section.
+ {
+ "nvim-telescope/telescope.nvim",
+ dependencies = {
+ {
+ "debugloop/telescope-undo.nvim",
+ cmd = "Telescope",
+ },
+ {
+ "nvim-telescope/telescope-fzf-native.nvim",
+ enabled = vim.fn.executable "make" == 1,
+ build = "make",
+ },
+ },
+ cmd = "Telescope",
+ opts = function()
+ local get_icon = require("base.utils").get_icon
+ local actions = require("telescope.actions")
+ local mappings = {
+ i = {
+ ["<C-n>"] = actions.cycle_history_next,
+ ["<C-p>"] = actions.cycle_history_prev,
+ ["<C-j>"] = actions.move_selection_next,
+ ["<C-k>"] = actions.move_selection_previous,
+ ["<ESC>"] = actions.close,
+ ["<C-c>"] = false,
+ },
+ n = { ["q"] = actions.close },
+ }
+ return {
+ defaults = {
+ prompt_prefix = get_icon("Selected", 1),
+ selection_caret = get_icon("Selected", 1),
+ multi_icon = get_icon("selected", 1),
+ path_display = { "truncate" },
+ sorting_strategy = "ascending",
+ layout_config = {
+ horizontal = {
+ prompt_position = "top",
+ preview_width = 0.50,
+ },
+ vertical = {
+ mirror = false,
+ },
+ width = 0.87,
+ height = 0.80,
+ preview_cutoff = 120,
+ },
+ mappings = mappings,
+ },
+ extensions = {
+ undo = {
+ use_delta = true,
+ side_by_side = true,
+ diff_context_lines = 0,
+ entry_format = " #$ID, $STAT, $TIME",
+ layout_strategy = "horizontal",
+ layout_config = {
+ preview_width = 0.65,
+ },
+ mappings = {
+ i = {
+ ["<cr>"] = require("telescope-undo.actions").yank_additions,
+ ["<S-cr>"] = require("telescope-undo.actions").yank_deletions,
+ ["<C-cr>"] = require("telescope-undo.actions").restore,
+ },
+ },
+ },
+ },
+ }
+ end,
+ config = function(_, opts)
+ local telescope = require("telescope")
+ telescope.setup(opts)
+ -- Here we define the Telescope extension for all plugins.
+ -- If you delete a plugin, you can also delete its Telescope extension.
+ if utils.is_available("nvim-notify") then telescope.load_extension("notify") end
+ if utils.is_available("telescope-fzf-native.nvim") then telescope.load_extension("fzf") end
+ if utils.is_available("telescope-undo.nvim") then telescope.load_extension("undo") end
+ if utils.is_available("project.nvim") then telescope.load_extension("projects") end
+ if utils.is_available("LuaSnip") then telescope.load_extension("luasnip") end
+ if utils.is_available("aerial.nvim") then telescope.load_extension("aerial") end
+ if utils.is_available("nvim-neoclip.lua") then
+ telescope.load_extension("neoclip")
+ telescope.load_extension("macroscope")
+ end
+ end,
+ },
+
+ -- [better ui elements]
+ -- https://github.com/stevearc/dressing.nvim
+ {
+ "stevearc/dressing.nvim",
+ event = "User BaseDefered",
+ opts = {
+ input = { default_prompt = "➤ " },
+ select = { backend = { "telescope", "builtin" } },
+ }
+ },
+
+ -- Noice.nvim [better cmd/search line]
+ -- https://github.com/folke/noice.nvim
+ -- We use it for:
+ -- * cmdline: Display treesitter for :
+ -- * search: Display a magnifier instead of /
+ --
+ -- We don't use it for:
+ -- * LSP status: We use a heirline component for this.
+ -- * Search results: We use a heirline component for this.
+ {
+ "folke/noice.nvim",
+ event = "User BaseDefered",
+ opts = function()
+ local enable_conceal = false -- Hide command text if true
+ return {
+ presets = { bottom_search = true }, -- The kind of popup used for /
+ cmdline = {
+ view = "cmdline", -- The kind of popup used for :
+ format = {
+ cmdline = { conceal = enable_conceal },
+ search_down = { conceal = enable_conceal },
+ search_up = { conceal = enable_conceal },
+ filter = { conceal = enable_conceal },
+ lua = { conceal = enable_conceal },
+ help = { conceal = enable_conceal },
+ input = { conceal = enable_conceal },
+ }
+ },
+
+ -- Disable every other noice feature
+ messages = { enabled = false },
+ lsp = {
+ hover = { enabled = false },
+ signature = { enabled = false },
+ progress = { enabled = false },
+ message = { enabled = false },
+ smart_move = { enabled = false },
+ },
+ }
+ end
+ },
+
+ -- UI icons [icons]
+ -- https://github.com/nvim-tree/nvim-web-devicons
+ {
+ "nvim-tree/nvim-web-devicons",
+ enabled = vim.g.icons_enabled,
+ event = "User BaseDefered",
+ opts = {
+ override = {
+ default_icon = {
+ icon = require("base.utils").get_icon("DefaultFile"),
+ name = "default"
+ },
+ deb = { icon = "", name = "Deb" },
+ lock = { icon = "", name = "Lock" },
+ mp3 = { icon = "", name = "Mp3" },
+ mp4 = { icon = "", name = "Mp4" },
+ out = { icon = "", name = "Out" },
+ ["robots.txt"] = { icon = "", name = "Robots" },
+ ttf = { icon = "", name = "TrueTypeFont" },
+ rpm = { icon = "", name = "Rpm" },
+ woff = { icon = "", name = "WebOpenFontFormat" },
+ woff2 = { icon = "", name = "WebOpenFontFormat2" },
+ xz = { icon = "", name = "Xz" },
+ zip = { icon = "", name = "Zip" },
+ },
+ },
+ config = function(_, opts)
+ require("nvim-web-devicons").setup(opts)
+ pcall(vim.api.nvim_del_user_command, "NvimWebDeviconsHiTest")
+ end
+ },
+
+ -- LSP icons [icons]
+ -- https://github.com/onsails/lspkind.nvim
+ {
+ "onsails/lspkind.nvim",
+ opts = {
+ mode = "symbol",
+ symbol_map = {
+ Array = "",
+ Boolean = "⊨",
+ Class = "",
+ Constructor = "",
+ Key = "",
+ Namespace = "",
+ Null = "NULL",
+ Number = "#",
+ Object = "",
+ Package = "",
+ Property = "",
+ Reference = "",
+ Snippet = "",
+ String = "",
+ TypeParameter = "",
+ Unit = "",
+ },
+ menu = {},
+ },
+ enabled = vim.g.icons_enabled,
+ config = function(_, opts)
+ require("lspkind").init(opts)
+ end,
+ },
+
+ -- nvim-scrollbar [scrollbar]
+ -- https://github.com/petertriho/nvim-scrollbar
+ {
+ "petertriho/nvim-scrollbar",
+ event = "User BaseFile",
+ opts = {
+ handlers = {
+ gitsigns = true, -- gitsigns integration (display hunks)
+ ale = true, -- lsp integration (display errors/warnings)
+ search = false, -- hlslens integration (display search result)
+ },
+ excluded_filetypes = {
+ "cmp_docs",
+ "cmp_menu",
+ "noice",
+ "prompt",
+ "TelescopePrompt",
+ "alpha",
+ },
+ },
+ },
+
+ -- mini.animate [animations]
+ -- https://github.com/echasnovski/mini.animate
+ -- HINT: if one of your personal keymappings fail due to mini.animate, try to
+ -- disable it during the keybinding using vim.g.minianimate_disable = true
+ {
+ "echasnovski/mini.animate",
+ event = "User BaseFile",
+ enabled = not is_android,
+ opts = function()
+ -- 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({ "", "i" }, key, function()
+ mouse_scrolled = true
+ return key
+ end, { expr = true })
+ end
+
+ local animate = require("mini.animate")
+ return {
+ open = { enable = false }, -- true causes issues on nvim-spectre
+ resize = {
+ timing = animate.gen_timing.linear { duration = 33, unit = "total" },
+ },
+ scroll = {
+ timing = animate.gen_timing.linear { duration = 50, 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,
+ },
+ },
+ cursor = {
+ enable = false, -- We don't want cursor ghosting
+ timing = animate.gen_timing.linear { duration = 26, unit = "total" },
+ },
+ }
+ end,
+ },
+
+ -- highlight-undo
+ -- https://github.com/tzachar/highlight-undo.nvim
+ -- This plugin only flases on redo.
+ -- But we also have a autocmd to flash on yank.
+ {
+ "tzachar/highlight-undo.nvim",
+ event = "User BaseDefered",
+ opts = {
+ hlgroup = "CurSearch",
+ duration = 150,
+ keymaps = {
+ { "n", "u", "undo", {} }, -- If you remap undo/redo, change this
+ { "n", "<C-r>", "redo", {} },
+ },
+ },
+ config = function(_, opts)
+ require("highlight-undo").setup(opts)
+
+ -- Also flash on yank.
+ vim.api.nvim_create_autocmd("TextYankPost", {
+ desc = "Highlight yanked text",
+ pattern = "*",
+ callback = function() vim.highlight.on_yank() end,
+ })
+ end,
+ },
+
+ -- which-key.nvim [on-screen keybindings]
+ -- https://github.com/folke/which-key.nvim
+ {
+ "folke/which-key.nvim",
+ event = "User BaseDefered",
+ opts = {
+ icons = { group = vim.g.icons_enabled and "" or "+", separator = "" },
+ disable = { filetypes = { "TelescopePrompt" } },
+ },
+ config = function(_, opts)
+ require("which-key").setup(opts)
+ require("base.utils").which_key_register()
+ end,
+ },
+
+
+} -- end of return
@@ -0,0 +1,510 @@
+-- Dev core
+-- Things that are just there.
+
+-- Sections:
+-- ## TREE SITTER
+-- -> nvim-treesitter [syntax highlight]
+-- -> nvim-ts-autotag [treesitter understand html tags]
+-- -> ts-comments.nvim [treesitter comments]
+-- -> nvim-colorizer [hex colors]
+
+-- ## LSP
+-- -> nvim-java [java support]
+-- -> mason-lspconfig [auto start lsp]
+-- -> nvim-lspconfig [lsp configs]
+-- -> mason.nvim [lsp package manager]
+-- -> SchemaStore.nvim [mason extra schemas]
+-- -> none-ls-autoload.nvim [mason package loader]
+-- -> none-ls [lsp code formatting]
+-- -> neodev [lsp for nvim lua api]
+-- -> garbage-day [lsp garbage collector]
+
+-- ## AUTO COMPLETION
+-- -> nvim-cmp [auto completion engine]
+-- -> cmp-nvim-buffer [auto completion buffer]
+-- -> cmp-nvim-path [auto completion path]
+-- -> cmp-nvim-lsp [auto completion lsp]
+-- -> cmp-luasnip [auto completion snippets]
+
+local utils = require("base.utils")
+local utils_lsp = require("base.utils.lsp")
+
+return {
+ -- TREE SITTER ---------------------------------------------------------
+ -- [syntax highlight] + [treesitter understand html tags] + [comments]
+ -- https://github.com/nvim-treesitter/nvim-treesitter
+ -- https://github.com/windwp/nvim-ts-autotag
+ -- https://github.com/windwp/nvim-treesitter-textobjects
+ {
+ "nvim-treesitter/nvim-treesitter",
+ dependencies = {
+ "windwp/nvim-ts-autotag",
+ "nvim-treesitter/nvim-treesitter-textobjects",
+ },
+ event = "User BaseDefered",
+ cmd = {
+ "TSBufDisable",
+ "TSBufEnable",
+ "TSBufToggle",
+ "TSDisable",
+ "TSEnable",
+ "TSToggle",
+ "TSInstall",
+ "TSInstallInfo",
+ "TSInstallSync",
+ "TSModuleInfo",
+ "TSUninstall",
+ "TSUpdate",
+ "TSUpdateSync",
+ },
+ build = ":TSUpdate",
+ init = function(plugin)
+ -- perf: make treesitter queries available at startup.
+ require("lazy.core.loader").add_to_rtp(plugin)
+ require("nvim-treesitter.query_predicates")
+ end,
+ opts = {
+ auto_install = false, -- Currently bugged. Use [:TSInstall all] and [:TSUpdate all]
+ autotag = { enable = true },
+ highlight = {
+ enable = true,
+ disable = function(_, bufnr)
+ local excluded_filetypes = {} -- disabled for
+ local is_disabled = vim.tbl_contains(
+ excluded_filetypes, vim.bo.filetype) or utils.is_big_file(bufnr)
+ return is_disabled
+ end,
+ },
+ matchup = {
+ enable = true,
+ enable_quotes = true,
+ disable = function(_, bufnr)
+ local excluded_filetypes = {} -- disabled for
+ local is_disabled = vim.tbl_contains(
+ excluded_filetypes, vim.bo.filetype) or utils.is_big_file(bufnr)
+ return is_disabled
+ end,
+ },
+ incremental_selection = { enable = true },
+ indent = { enable = true },
+ textobjects = {
+ select = {
+ enable = true,
+ lookahead = true,
+ keymaps = {
+ ["ak"] = { query = "@block.outer", desc = "around block" },
+ ["ik"] = { query = "@block.inner", desc = "inside block" },
+ ["ac"] = { query = "@class.outer", desc = "around class" },
+ ["ic"] = { query = "@class.inner", desc = "inside class" },
+ ["a?"] = { query = "@conditional.outer", desc = "around conditional" },
+ ["i?"] = { query = "@conditional.inner", desc = "inside conditional" },
+ ["af"] = { query = "@function.outer", desc = "around function " },
+ ["if"] = { query = "@function.inner", desc = "inside function " },
+ ["al"] = { query = "@loop.outer", desc = "around loop" },
+ ["il"] = { query = "@loop.inner", desc = "inside loop" },
+ ["aa"] = { query = "@parameter.outer", desc = "around argument" },
+ ["ia"] = { query = "@parameter.inner", desc = "inside argument" },
+ },
+ },
+ move = {
+ enable = true,
+ set_jumps = true,
+ goto_next_start = {
+ ["]k"] = { query = "@block.outer", desc = "Next block start" },
+ ["]f"] = { query = "@function.outer", desc = "Next function start" },
+ ["]a"] = { query = "@parameter.inner", desc = "Next parameter start" },
+ },
+ goto_next_end = {
+ ["]K"] = { query = "@block.outer", desc = "Next block end" },
+ ["]F"] = { query = "@function.outer", desc = "Next function end" },
+ ["]A"] = { query = "@parameter.inner", desc = "Next parameter end" },
+ },
+ goto_previous_start = {
+ ["[k"] = { query = "@block.outer", desc = "Previous block start" },
+ ["[f"] = { query = "@function.outer", desc = "Previous function start" },
+ ["[a"] = { query = "@parameter.inner", desc = "Previous parameter start" },
+ },
+ goto_previous_end = {
+ ["[K"] = { query = "@block.outer", desc = "Previous block end" },
+ ["[F"] = { query = "@function.outer", desc = "Previous function end" },
+ ["[A"] = { query = "@parameter.inner", desc = "Previous parameter end" },
+ },
+ },
+ swap = {
+ enable = true,
+ swap_next = {
+ [">K"] = { query = "@block.outer", desc = "Swap next block" },
+ [">F"] = { query = "@function.outer", desc = "Swap next function" },
+ [">A"] = { query = "@parameter.inner", desc = "Swap next parameter" },
+ },
+ swap_previous = {
+ ["<K"] = { query = "@block.outer", desc = "Swap previous block" },
+ ["<F"] = { query = "@function.outer", desc = "Swap previous function" },
+ ["<A"] = { query = "@parameter.inner", desc = "Swap previous parameter" },
+ },
+ },
+ },
+ },
+ },
+
+ -- ts-comments.nvim [treesitter comments]
+ -- https://github.com/folke/ts-comments.nvim
+ -- This plugin can be safely removed after nvim 0.11 is released.
+ {
+ "folke/ts-comments.nvim",
+ event = "User BaseFile",
+ enabled = vim.fn.has("nvim-0.10.0") == 1,
+ opts = {},
+ },
+
+ -- [hex colors]
+ -- https://github.com/NvChad/nvim-colorizer.lua
+ {
+ "NvChad/nvim-colorizer.lua",
+ event = "User BaseFile",
+ cmd = {
+ "ColorizerToggle",
+ "ColorizerAttachToBuffer",
+ "ColorizerDetachFromBuffer",
+ "ColorizerReloadAllBuffers",
+ },
+ opts = { user_default_options = { names = false } },
+ },
+
+ -- LSP -------------------------------------------------------------------
+
+ -- nvim-java [java support]
+ -- https://github.com/nvim-java/nvim-java
+ -- Reliable jdtls support. Must go before mason-lspconfig and lsp-config.
+ {
+ "nvim-java/nvim-java",
+ ft = { "java" },
+ dependencies = {
+ "nvim-java/lua-async-await",
+ 'nvim-java/nvim-java-refactor',
+ "nvim-java/nvim-java-core",
+ "nvim-java/nvim-java-test",
+ "nvim-java/nvim-java-dap",
+ "MunifTanjim/nui.nvim",
+ "neovim/nvim-lspconfig",
+ "mfussenegger/nvim-dap",
+ "williamboman/mason.nvim",
+ },
+ opts = {
+ notifications = {
+ dap = false,
+ },
+ -- NOTE: One of these files must be in your project root directory.
+ -- Otherwise the debugger will end in the wrong directory and fail.
+ root_markers = {
+ 'settings.gradle',
+ 'settings.gradle.kts',
+ 'pom.xml',
+ 'build.gradle',
+ 'mvnw',
+ 'gradlew',
+ 'build.gradle',
+ 'build.gradle.kts',
+ '.git',
+ },
+ },
+ },
+
+ -- nvim-lspconfig [lsp configs]
+ -- https://github.com/neovim/nvim-lspconfig
+ -- This plugin provide default configs for the lsp servers available on mason.
+ {
+ "neovim/nvim-lspconfig",
+ event = "User BaseFile",
+ dependencies = "nvim-java/nvim-java",
+ },
+
+ -- mason-lspconfig [auto start lsp]
+ -- https://github.com/williamboman/mason-lspconfig.nvim
+ -- This plugin auto starts the lsp servers installed by Mason
+ -- every time Neovim trigger the event FileType.
+ {
+ "williamboman/mason-lspconfig.nvim",
+ dependencies = { "neovim/nvim-lspconfig" },
+ event = "User BaseFile",
+ opts = function(_, opts)
+ if not opts.handlers then opts.handlers = {} end
+ opts.handlers[1] = function(server) utils_lsp.setup(server) end
+ end,
+ config = function(_, opts)
+ require("mason-lspconfig").setup(opts)
+ utils_lsp.apply_default_lsp_settings() -- Apply our default lsp settings.
+ utils.trigger_event("FileType") -- This line starts this plugin.
+ end,
+ },
+
+ -- mason [lsp package manager]
+ -- https://github.com/williamboman/mason.nvim
+ -- https://github.com/zeioth/mason-extra-cmds
+ {
+ "williamboman/mason.nvim",
+ dependencies = { "zeioth/mason-extra-cmds", opts = {} },
+ cmd = {
+ "Mason",
+ "MasonInstall",
+ "MasonUninstall",
+ "MasonUninstallAll",
+ "MasonLog",
+ "MasonUpdate",
+ "MasonUpdateAll", -- this cmd is provided by mason-extra-cmds
+ },
+ opts = {
+ registries = {
+ "github:nvim-java/mason-registry",
+ "github:mason-org/mason-registry",
+ },
+ ui = {
+ icons = {
+ package_installed = "✓",
+ package_uninstalled = "✗",
+ package_pending = "⟳",
+ },
+ },
+ }
+ },
+
+ -- Schema Store [mason extra schemas]
+ -- https://github.com/b0o/SchemaStore.nvim
+ "b0o/SchemaStore.nvim",
+
+ -- none-ls-autoload.nvim [mason package loader]
+ -- https://github.com/zeioth/mason-none-ls.nvim
+ -- This plugin auto starts the packages installed by Mason
+ -- every time Neovim trigger the event FileType ().
+ -- By default it will use none-ls builtin sources.
+ -- But you can add external sources if a mason package has no builtin support.
+ {
+ "zeioth/none-ls-autoload.nvim",
+ event = "User BaseFile",
+ dependencies = {
+ "williamboman/mason.nvim",
+ "zeioth/none-ls-external-sources.nvim"
+ },
+ opts = {
+ -- Here you can add support for sources not oficially suppored by none-ls.
+ external_sources = {
+ -- diagnostics
+ 'none-ls-external-sources.diagnostics.cpplint',
+ 'none-ls-external-sources.diagnostics.eslint',
+ 'none-ls-external-sources.diagnostics.eslint_d',
+ 'none-ls-external-sources.diagnostics.flake8',
+ 'none-ls-external-sources.diagnostics.luacheck',
+ 'none-ls-external-sources.diagnostics.psalm',
+ 'none-ls-external-sources.diagnostics.shellcheck',
+ 'none-ls-external-sources.diagnostics.yamllint',
+
+ -- formatting
+ 'none-ls-external-sources.formatting.autopep8',
+ 'none-ls-external-sources.formatting.beautysh',
+ 'none-ls-external-sources.formatting.easy-coding-standard',
+ 'none-ls-external-sources.formatting.eslint',
+ 'none-ls-external-sources.formatting.eslint_d',
+ 'none-ls-external-sources.formatting.jq',
+ 'none-ls-external-sources.formatting.latexindent',
+ 'none-ls-external-sources.formatting.reformat_gherkin',
+ 'none-ls-external-sources.formatting.rustfmt',
+ 'none-ls-external-sources.formatting.standardrb',
+ 'none-ls-external-sources.formatting.yq',
+ },
+ },
+ },
+
+ -- none-ls [lsp code formatting]
+ -- https://github.com/nvimtools/none-ls.nvim
+ {
+ "nvimtools/none-ls.nvim",
+ event = "User BaseFile",
+ opts = function()
+ local builtin_sources = require("null-ls").builtins
+
+ -- You can customize your 'builtin sources' and 'external sources' here.
+ builtin_sources.formatting.shfmt.with({
+ command = "shfmt",
+ args = { "-i", "2", "-filename", "$FILENAME" },
+ })
+
+ -- Attach the user lsp mappings to every none-ls client.
+ return { on_attach = utils_lsp.apply_user_lsp_mappings }
+ end
+ },
+
+ -- neodev.nvim [lsp for nvim lua api]
+ -- https://github.com/folke/neodev.nvim
+ {
+ "folke/neodev.nvim",
+ ft = { "lua" },
+ opts = {}
+ },
+
+ -- garbage-day.nvim [lsp garbage collector]
+ -- https://github.com/zeioth/garbage-day.nvim
+ {
+ "zeioth/garbage-day.nvim",
+ event = "User BaseFile",
+ opts = {
+ aggressive_mode = false,
+ excluded_lsp_clients = {
+ "null-ls", "jdtls", "marksman"
+ },
+ grace_period = (60 * 15),
+ wakeup_delay = 3000,
+ notifications = false,
+ retries = 3,
+ timeout = 1000,
+ }
+ },
+
+ -- AUTO COMPLETION --------------------------------------------------------
+ -- Auto completion engine [autocompletion engine]
+ -- https://github.com/hrsh7th/nvim-cmp
+ {
+ "hrsh7th/nvim-cmp",
+ dependencies = {
+ "saadparwaiz1/cmp_luasnip",
+ "hrsh7th/cmp-buffer",
+ "hrsh7th/cmp-path",
+ "hrsh7th/cmp-nvim-lsp"
+ },
+ event = "InsertEnter",
+ opts = function()
+ -- ensure dependencies exist
+ local cmp = require("cmp")
+ local luasnip = require("luasnip")
+ local lspkind = require("lspkind")
+
+ -- border opts
+ local border_opts = {
+ border = "rounded",
+ winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder,CursorLine:PmenuSel,Search:None",
+ }
+
+ -- helper
+ local function has_words_before()
+ 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
+
+ return {
+ enabled = function() -- disable in certain cases on dap.
+ local is_prompt = vim.bo.buftype == "prompt"
+ local is_dap_prompt = utils.is_available("cmp-dap")
+ and vim.tbl_contains(
+ { "dap-repl", "dapui_watches", "dapui_hover" }, vim.bo.filetype)
+ if is_prompt and not is_dap_prompt then
+ return false
+ else
+ return vim.g.cmp_enabled
+ end
+ end,
+ preselect = cmp.PreselectMode.None,
+ formatting = {
+ fields = { "kind", "abbr", "menu" },
+ format = lspkind.cmp_format(utils.get_plugin_opts("lspkind.nvim")),
+ },
+ snippet = {
+ expand = function(args) luasnip.lsp_expand(args.body) end,
+ },
+ duplicates = {
+ nvim_lsp = 1,
+ luasnip = 1,
+ cmp_tabnine = 1,
+ buffer = 1,
+ path = 1,
+ },
+ confirm_opts = {
+ behavior = cmp.ConfirmBehavior.Replace,
+ select = false,
+ },
+ window = {
+ completion = cmp.config.window.bordered(border_opts),
+ documentation = cmp.config.window.bordered(border_opts),
+ },
+ mapping = {
+ ["<PageUp>"] = cmp.mapping.select_prev_item {
+ behavior = cmp.SelectBehavior.Select,
+ count = 8,
+ },
+ ["<PageDown>"] = cmp.mapping.select_next_item {
+ behavior = cmp.SelectBehavior.Select,
+ count = 8,
+ },
+ ["<C-PageUp>"] = cmp.mapping.select_prev_item {
+ behavior = cmp.SelectBehavior.Select,
+ count = 16,
+ },
+ ["<C-PageDown>"] = cmp.mapping.select_next_item {
+ behavior = cmp.SelectBehavior.Select,
+ count = 16,
+ },
+ ["<S-PageUp>"] = cmp.mapping.select_prev_item {
+ behavior = cmp.SelectBehavior.Select,
+ count = 16,
+ },
+ ["<S-PageDown>"] = cmp.mapping.select_next_item {
+ behavior = cmp.SelectBehavior.Select,
+ count = 16,
+ },
+ ["<Up>"] = cmp.mapping.select_prev_item {
+ behavior = cmp.SelectBehavior.Select,
+ },
+ ["<Down>"] = cmp.mapping.select_next_item {
+ behavior = cmp.SelectBehavior.Select,
+ },
+ ["<C-p>"] = cmp.mapping.select_prev_item {
+ behavior = cmp.SelectBehavior.Insert,
+ },
+ ["<C-n>"] = cmp.mapping.select_next_item {
+ behavior = cmp.SelectBehavior.Insert,
+ },
+ ["<C-k>"] = cmp.mapping.select_prev_item {
+ behavior = cmp.SelectBehavior.Insert,
+ },
+ ["<C-j>"] = cmp.mapping.select_next_item {
+ behavior = cmp.SelectBehavior.Insert,
+ },
+ ["<C-u>"] = cmp.mapping(cmp.mapping.scroll_docs(-4), { "i", "c" }),
+ ["<C-d>"] = cmp.mapping(cmp.mapping.scroll_docs(4), { "i", "c" }),
+ ["<C-Space>"] = cmp.mapping(cmp.mapping.complete(), { "i", "c" }),
+ ["<C-y>"] = cmp.config.disable,
+ ["<C-e>"] = cmp.mapping {
+ i = cmp.mapping.abort(),
+ c = cmp.mapping.close(),
+ },
+ ["<CR>"] = cmp.mapping.confirm { select = false },
+ ["<Tab>"] = cmp.mapping(function(fallback)
+ if cmp.visible() then
+ cmp.select_next_item()
+ 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()
+ elseif luasnip.jumpable(-1) then
+ luasnip.jump(-1)
+ else
+ fallback()
+ end
+ end, { "i", "s" }),
+ },
+ sources = cmp.config.sources {
+ { name = "nvim_lsp", priority = 1000 },
+ { name = "luasnip", priority = 750 },
+ { name = "buffer", priority = 500 },
+ { name = "path", priority = 250 },
+ },
+ }
+ end,
+ },
+
+}
@@ -0,0 +1,901 @@
+-- Dev
+-- Things you actively use for coding.
+
+-- Sections:
+-- ## SNIPPETS
+-- -> luasnip [snippet engine]
+-- -> friendly-snippets [snippet templates]
+
+-- ## GIT
+-- -> gitsigns.nvim [git hunks]
+-- -> fugitive.vim [git commands]
+
+-- ## ANALYZER
+-- -> aerial.nvim [symbols tree]
+-- -> litee-calltree.nvim [calltree]
+
+-- ## CODE DOCUMENTATION
+-- -> dooku.nvim [html doc generator]
+-- -> markdown-preview.nvim [markdown previewer]
+-- -> markmap.nvim [markdown mindmap]
+
+-- ## ARTIFICIAL INTELLIGENCE
+-- -> neural [chatgpt code generator]
+-- -> copilot [github code suggestions]
+-- -> guess-indent [guess-indent]
+
+-- ## COMPILER
+-- -> compiler.nvim [compiler]
+-- -> overseer.nvim [task runner]
+
+-- ## DEBUGGER
+-- -> nvim-dap [debugger]
+
+-- ## TESTING
+-- -> neotest.nvim [unit testing]
+-- -> nvim-coverage [code coverage]
+
+-- ## LANGUAGE IMPROVEMENTS
+-- -> guttentags_plus [auto generate C/C++ tags]
+
+local is_windows = vim.fn.has('win32') == 1 -- true if on windows
+
+return {
+ -- SNIPPETS ----------------------------------------------------------------
+ -- Vim Snippets engine [snippet engine] + [snippet templates]
+ -- https://github.com/L3MON4D3/LuaSnip
+ -- https://github.com/rafamadriz/friendly-snippets
+ {
+ "L3MON4D3/LuaSnip",
+ build = not is_windows and "make install_jsregexp" or nil,
+ dependencies = {
+ "rafamadriz/friendly-snippets",
+ "zeioth/NormalSnippets",
+ "benfowler/telescope-luasnip.nvim",
+ },
+ event = "User BaseFile",
+ opts = {
+ history = true,
+ delete_check_events = "TextChanged",
+ region_check_events = "CursorMoved",
+ },
+ config = function(_, opts)
+ if opts then require("luasnip").config.setup(opts) end
+ vim.tbl_map(
+ function(type) require("luasnip.loaders.from_" .. type).lazy_load() end,
+ { "vscode", "snipmate", "lua" }
+ )
+ -- friendly-snippets - enable standardized comments snippets
+ require("luasnip").filetype_extend("typescript", { "tsdoc" })
+ require("luasnip").filetype_extend("javascript", { "jsdoc" })
+ require("luasnip").filetype_extend("lua", { "luadoc" })
+ require("luasnip").filetype_extend("python", { "pydoc" })
+ require("luasnip").filetype_extend("rust", { "rustdoc" })
+ require("luasnip").filetype_extend("cs", { "csharpdoc" })
+ require("luasnip").filetype_extend("java", { "javadoc" })
+ require("luasnip").filetype_extend("c", { "cdoc" })
+ require("luasnip").filetype_extend("cpp", { "cppdoc" })
+ require("luasnip").filetype_extend("php", { "phpdoc" })
+ require("luasnip").filetype_extend("kotlin", { "kdoc" })
+ require("luasnip").filetype_extend("ruby", { "rdoc" })
+ require("luasnip").filetype_extend("sh", { "shelldoc" })
+ end,
+ },
+
+ -- GIT ---------------------------------------------------------------------
+ -- Git signs [git hunks]
+ -- https://github.com/lewis6991/gitsigns.nvim
+ {
+ "lewis6991/gitsigns.nvim",
+ enabled = vim.fn.executable "git" == 1,
+ event = "User BaseGitFile",
+ opts = function()
+ local get_icon = require("base.utils").get_icon
+ return {
+ max_file_length = vim.g.big_file.lines,
+ signs = {
+ add = { text = get_icon("GitSign") },
+ change = { text = get_icon("GitSign") },
+ delete = { text = get_icon("GitSign") },
+ topdelete = { text = get_icon("GitSign") },
+ changedelete = { text = get_icon("GitSign") },
+ untracked = { text = get_icon("GitSign") },
+ },
+ }
+ end
+ },
+
+ -- Git fugitive mergetool + [git commands]
+ -- https://github.com/lewis6991/gitsigns.nvim
+ -- PR needed: Setup keymappings to move quickly when using this feature.
+ --
+ -- We only want this plugin to use it as mergetool like "git mergetool".
+ -- To enable this feature, add this to your global .gitconfig:
+ --
+ -- [mergetool "fugitive"]
+ -- cmd = nvim -c \"Gvdiffsplit!\" \"$MERGED\"
+ -- [merge]
+ -- tool = fugitive
+ -- [mergetool]
+ -- keepBackup = false
+ {
+ "tpope/vim-fugitive",
+ enabled = vim.fn.executable "git" == 1,
+ dependencies = { "tpope/vim-rhubarb" },
+ cmd = {
+ "Gvdiffsplit",
+ "Gdiffsplit",
+ "Gedit",
+ "Gsplit",
+ "Gread",
+ "Gwrite",
+ "Ggrep",
+ "GMove",
+ "GRename",
+ "GDelete",
+ "GRemove",
+ "GBrowse",
+ "Git",
+ "Gstatus",
+ },
+ config = function()
+ -- NOTE: On vimplugins we use config instead of opts.
+ vim.g.fugitive_no_maps = 1
+ end,
+ },
+
+ -- ANALYZER ----------------------------------------------------------------
+ -- [symbols tree]
+ -- https://github.com/stevearc/aerial.nvim
+ {
+ "stevearc/aerial.nvim",
+ event = "User BaseFile",
+ opts = {
+ filter_kind = { -- Symbols that will appear on the tree
+ -- "Class",
+ "Constructor",
+ "Enum",
+ "Function",
+ "Interface",
+ -- "Module",
+ "Method",
+ -- "Struct",
+ },
+ open_automatic = false, -- Open if the buffer is compatible
+ autojump = true,
+ link_folds_to_tree = false,
+ link_tree_to_folds = false,
+ attach_mode = "global",
+ backends = { "lsp", "treesitter", "markdown", "man" },
+ disable_max_lines = vim.g.big_file.lines,
+ disable_max_size = vim.g.big_file.size,
+ layout = {
+ min_width = 28,
+ default_direction = "right",
+ placement = "edge",
+ },
+ show_guides = true,
+ guides = {
+ mid_item = "├ ",
+ last_item = "└ ",
+ nested_top = "│ ",
+ whitespace = " ",
+ },
+ keymaps = {
+ ["[y"] = "actions.prev",
+ ["]y"] = "actions.next",
+ ["[Y"] = "actions.prev_up",
+ ["]Y"] = "actions.next_up",
+ ["{"] = false,
+ ["}"] = false,
+ ["[["] = false,
+ ["]]"] = false,
+ },
+ },
+ config = function(_, opts)
+ require("aerial").setup(opts)
+ -- HACK: The first time you open aerial on a session, close all folds.
+ vim.api.nvim_create_autocmd({"FileType", "BufEnter"}, {
+ desc = "Aerial: When aerial is opened, close all its folds.",
+ callback = function()
+ local is_aerial = vim.bo.filetype == "aerial"
+ local is_ufo_available = require("base.utils").is_available("nvim-ufo")
+ if is_ufo_available and is_aerial and vim.b.new_aerial_session == nil then
+ vim.b.new_aerial_session = false
+ require("aerial").tree_set_collapse_level(0, 0)
+ end
+ end,
+ })
+ end
+ },
+
+ -- Litee calltree [calltree]
+ -- https://github.com/ldelossa/litee.nvim
+ -- https://github.com/ldelossa/litee-calltree.nvim
+ -- press ? inside the panel to show help.
+ {
+ 'ldelossa/litee.nvim',
+ event = "User BaseFile",
+ opts = {
+ notify = { enabled = false },
+ panel = {
+ orientation = "bottom",
+ panel_size = 10,
+ },
+ },
+ config = function(_, opts)
+ require('litee.lib').setup(opts)
+ end
+ },
+ {
+ 'ldelossa/litee-calltree.nvim',
+ dependencies = 'ldelossa/litee.nvim',
+ event = "User BaseFile",
+ opts = {
+ on_open = "panel", -- or popout
+ map_resize_keys = false,
+ keymaps = {
+ expand = "<CR>",
+ collapse = "c",
+ collapse_all = "C",
+ jump = "<C-CR>"
+ },
+ },
+ config = function(_, opts)
+ require('litee.calltree').setup(opts)
+
+ -- Highlight only while on calltree
+ vim.api.nvim_create_autocmd({ "WinEnter" }, {
+ desc = "Clear highlights when leaving calltree + UX improvements.",
+ callback = function()
+ vim.defer_fn(function()
+ if vim.bo.filetype == "calltree" then
+ vim.wo.colorcolumn = "0"
+ vim.wo.foldcolumn = "0"
+ vim.cmd("silent! PinBuffer") -- stickybuf.nvim
+ vim.cmd("silent! hi LTSymbolJump ctermfg=015 ctermbg=110 cterm=italic,bold,underline guifg=#464646 guibg=#87afd7 gui=italic,bold")
+ vim.cmd("silent! hi LTSymbolJumpRefs ctermfg=015 ctermbg=110 cterm=italic,bold,underline guifg=#464646 guibg=#87afd7 gui=italic,bold")
+ else
+ vim.cmd("silent! highlight clear LTSymbolJump")
+ vim.cmd("silent! highlight clear LTSymbolJumpRefs")
+ end
+ end, 100)
+ end
+ })
+ end
+ },
+
+ -- CODE DOCUMENTATION ------------------------------------------------------
+ -- dooku.nvim [html doc generator]
+ -- https://github.com/zeioth/dooku.nvim
+ {
+ "zeioth/dooku.nvim",
+ cmd = {
+ "DookuGenerate",
+ "DookuOpen",
+ "DookuAutoSetup"
+ },
+ opts = {},
+ },
+
+ -- [markdown previewer]
+ -- https://github.com/iamcco/markdown-preview.nvim
+ -- Note: If you change the build command, wipe ~/.local/data/nvim/lazy
+ {
+ "iamcco/markdown-preview.nvim",
+ build = function() vim.fn["mkdp#util#install"]() end,
+ ft = { "markdown" },
+ cmd = {
+ "MarkdownPreview",
+ "MarkdownPreviewStop",
+ "MarkdownPreviewToggle",
+ },
+ },
+
+ -- [markdown markmap]
+ -- https://github.com/zeioth/markmap.nvim
+ -- Important: Make sure you have yarn in your PATH before running markmap.
+ {
+ "zeioth/markmap.nvim",
+ build = "yarn global add markmap-cli",
+ cmd = { "MarkmapOpen", "MarkmapSave", "MarkmapWatch", "MarkmapWatchStop" },
+ config = function(_, opts) require("markmap").setup(opts) end,
+ },
+
+ -- ARTIFICIAL INTELLIGENCE -------------------------------------------------
+ -- neural [chatgpt code generator]
+ -- https://github.com/dense-analysis/neural
+ --
+ -- NOTE: In order for this plugin to work, you will have to set
+ -- the next env var in your OS:
+ -- OPENAI_API_KEY="my_key_here"
+ {
+ "dense-analysis/neural",
+ cmd = { "Neural" },
+ config = function()
+ require("neural").setup {
+ source = {
+ openai = {
+ api_key = vim.env.OPENAI_API_KEY,
+ },
+ },
+ ui = {
+ prompt_icon = ">",
+ },
+ }
+ end,
+ },
+
+ -- copilot [github code suggestions]
+ -- https://github.com/github/copilot.vim
+ -- As alternative to chatgpt, you can use copilot uncommenting this.
+ -- Then you must run :Copilot setup
+ -- {
+ -- "github/copilot.vim",
+ -- event = "User BaseFile"
+ -- },
+ -- copilot-cmp
+ -- https://github.com/zbirenbaum/copilot-cmp
+ -- {
+ -- "zbirenbaum/copilot-cmp",
+ -- opts = { suggesion = { enabled = false }, panel = { enabled = false } },
+ -- config = function (_, opts) require("copilot_cmp").setup(opts) end
+ -- },
+
+ -- [guess-indent]
+ -- https://github.com/NMAC427/guess-indent.nvim
+ -- Note that this plugin won't autoformat the code.
+ -- It just set the buffer options to tabluate in a certain way.
+ {
+ "NMAC427/guess-indent.nvim",
+ event = "User BaseFile",
+ opts = {}
+ },
+
+ -- COMPILER ----------------------------------------------------------------
+ -- compiler.nvim [compiler]
+ -- https://github.com/zeioth/compiler.nvim
+ {
+ "zeioth/compiler.nvim",
+ cmd = {
+ "CompilerOpen",
+ "CompilerToggleResults",
+ "CompilerRedo",
+ "CompilerStop"
+ },
+ dependencies = { "stevearc/overseer.nvim" },
+ opts = {},
+ },
+
+ -- overseer [task runner]
+ -- https://github.com/stevearc/overseer.nvim
+ -- If you need to close a task immediately:
+ -- press ENTER in the output menu on the task you wanna close.
+ {
+ "stevearc/overseer.nvim",
+ cmd = {
+ "OverseerOpen",
+ "OverseerClose",
+ "OverseerToggle",
+ "OverseerSaveBundle",
+ "OverseerLoadBundle",
+ "OverseerDeleteBundle",
+ "OverseerRunCmd",
+ "OverseerRun",
+ "OverseerInfo",
+ "OverseerBuild",
+ "OverseerQuickAction",
+ "OverseerTaskAction",
+ "OverseerClearCache"
+ },
+ opts = {
+ task_list = { -- the window that shows the results.
+ direction = "bottom",
+ min_height = 25,
+ max_height = 25,
+ default_detail = 1,
+ },
+ -- component_aliases = {
+ -- default = {
+ -- -- Behaviors that will apply to all tasks.
+ -- "on_exit_set_status", -- don't delete this one.
+ -- "on_output_summarize", -- show last line on the list.
+ -- "display_duration", -- display duration.
+ -- "on_complete_notify", -- notify on task start.
+ -- "open_output", -- focus last executed task.
+ -- { "on_complete_dispose", timeout=300 }, -- dispose old tasks.
+ -- },
+ -- },
+ },
+ },
+
+ -- DEBUGGER ----------------------------------------------------------------
+ -- Debugger alternative to vim-inspector [debugger]
+ -- https://github.com/mfussenegger/nvim-dap
+ -- Here we configure the adapter+config of every debugger.
+ -- Debuggers don't have system dependencies, you just install them with mason.
+ -- We currently ship most of them with nvim.
+ {
+ "mfussenegger/nvim-dap",
+ enabled = vim.fn.has "win32" == 0,
+ event = "User BaseFile",
+ config = function()
+ local dap = require("dap")
+
+ -- C#
+ dap.adapters.coreclr = {
+ type = 'executable',
+ command = vim.fn.stdpath('data') .. '/mason/bin/netcoredbg',
+ args = { '--interpreter=vscode' }
+ }
+ dap.configurations.cs = {
+ {
+ type = "coreclr",
+ name = "launch - netcoredbg",
+ request = "launch",
+ program = function() -- Ask the user what executable wants to debug
+ return vim.fn.input('Path to dll: ', vim.fn.getcwd() .. '/bin/Program.exe', 'file')
+ end,
+ },
+ }
+
+ -- F#
+ dap.configurations.fsharp = dap.configurations.cs
+
+ -- Visual basic dotnet
+ dap.configurations.vb = dap.configurations.cs
+
+ -- Java
+ -- Note: The java debugger jdtls is automatically spawned and configured
+ -- by the plugin 'nvim-java' in './3-dev-core.lua'.
+
+ -- Python
+ dap.adapters.python = {
+ type = 'executable',
+ command = vim.fn.stdpath('data') .. '/mason/packages/debugpy/venv/bin/python',
+ args = { '-m', 'debugpy.adapter' },
+ }
+ dap.configurations.python = {
+ {
+ type = "python",
+ request = "launch",
+ name = "Launch file",
+ program = "${file}", -- This configuration will launch the current file if used.
+ },
+ }
+
+ -- Lua
+ dap.adapters.nlua = function(callback, config)
+ callback({ type = 'server', host = config.host or "127.0.0.1", port = config.port or 8086 })
+ end
+ dap.configurations.lua = {
+ {
+ type = 'nlua',
+ request = 'attach',
+ name = "Attach to running Neovim instance",
+ program = function() pcall(require "osv".launch({ port = 8086 })) end,
+ }
+ }
+
+ -- C
+ dap.adapters.codelldb = {
+ type = 'server',
+ port = "${port}",
+ executable = {
+ command = vim.fn.stdpath('data') .. '/mason/bin/codelldb',
+ args = { "--port", "${port}" },
+ detached = function() if is_windows then return false else return true end end,
+ }
+ }
+ dap.configurations.c = {
+ {
+ name = 'Launch',
+ type = 'codelldb',
+ request = 'launch',
+ program = function() -- Ask the user what executable wants to debug
+ return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/bin/program', 'file')
+ end,
+ cwd = '${workspaceFolder}',
+ stopOnEntry = false,
+ args = {},
+ },
+ }
+
+ -- C++
+ dap.configurations.cpp = dap.configurations.c
+
+ -- Rust
+ dap.configurations.rust = {
+ {
+ name = 'Launch',
+ type = 'codelldb',
+ request = 'launch',
+ program = function() -- Ask the user what executable wants to debug
+ return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/bin/program', 'file')
+ end,
+ cwd = '${workspaceFolder}',
+ stopOnEntry = false,
+ args = {},
+ initCommands = function() -- add rust types support (optional)
+ -- Find out where to look for the pretty printer Python module
+ local rustc_sysroot = vim.fn.trim(vim.fn.system('rustc --print sysroot'))
+
+ local script_import = 'command script import "' .. rustc_sysroot .. '/lib/rustlib/etc/lldb_lookup.py"'
+ local commands_file = rustc_sysroot .. '/lib/rustlib/etc/lldb_commands'
+
+ local commands = {}
+ local file = io.open(commands_file, 'r')
+ if file then
+ for line in file:lines() do
+ table.insert(commands, line)
+ end
+ file:close()
+ end
+ table.insert(commands, 1, script_import)
+
+ return commands
+ end,
+ }
+ }
+
+ -- Go
+ -- Requires:
+ -- * You have initialized your module with 'go mod init module_name'.
+ -- * You :cd your project before running DAP.
+ dap.adapters.delve = {
+ type = 'server',
+ port = '${port}',
+ executable = {
+ command = vim.fn.stdpath('data') .. '/mason/packages/delve/dlv',
+ args = { 'dap', '-l', '127.0.0.1:${port}' },
+ }
+ }
+ dap.configurations.go = {
+ {
+ type = "delve",
+ name = "Compile module and debug this file",
+ request = "launch",
+ program = "./${relativeFileDirname}",
+ },
+ {
+ type = "delve",
+ name = "Compile module and debug this file (test)",
+ request = "launch",
+ mode = "test",
+ program = "./${relativeFileDirname}"
+ },
+ }
+
+ -- Dart / Flutter
+ dap.adapters.dart = {
+ type = 'executable',
+ command = vim.fn.stdpath('data') .. '/mason/bin/dart-debug-adapter',
+ args = { 'dart' }
+ }
+ dap.adapters.flutter = {
+ type = 'executable',
+ command = vim.fn.stdpath('data') .. '/mason/bin/dart-debug-adapter',
+ args = { 'flutter' }
+ }
+ dap.configurations.dart = {
+ {
+ type = "dart",
+ request = "launch",
+ name = "Launch dart",
+ dartSdkPath = "/opt/flutter/bin/cache/dart-sdk/", -- ensure this is correct
+ flutterSdkPath = "/opt/flutter", -- ensure this is correct
+ program = "${workspaceFolder}/lib/main.dart", -- ensure this is correct
+ cwd = "${workspaceFolder}",
+ },
+ {
+ type = "flutter",
+ request = "launch",
+ name = "Launch flutter",
+ dartSdkPath = "/opt/flutter/bin/cache/dart-sdk/", -- ensure this is correct
+ flutterSdkPath = "/opt/flutter", -- ensure this is correct
+ program = "${workspaceFolder}/lib/main.dart", -- ensure this is correct
+ cwd = "${workspaceFolder}",
+ }
+ }
+
+ -- Kotlin
+ -- Kotlin projects have very weak project structure conventions.
+ -- You must manually specify what the project root and main class are.
+ dap.adapters.kotlin = {
+ type = 'executable',
+ command = vim.fn.stdpath('data') .. '/mason/bin/kotlin-debug-adapter',
+ }
+ dap.configurations.kotlin = {
+ {
+ type = 'kotlin',
+ request = 'launch',
+ name = 'Launch kotlin program',
+ projectRoot = "${workspaceFolder}/app", -- ensure this is correct
+ mainClass = "AppKt", -- ensure this is correct
+ },
+ }
+
+ -- Javascript / Typescript (firefox)
+ dap.adapters.firefox = {
+ type = 'executable',
+ command = vim.fn.stdpath('data') .. '/mason/bin/firefox-debug-adapter',
+ }
+ dap.configurations.typescript = {
+ {
+ name = 'Debug with Firefox',
+ type = 'firefox',
+ request = 'launch',
+ reAttach = true,
+ url = 'http://localhost:4200', -- Write the actual URL of your project.
+ webRoot = '${workspaceFolder}',
+ firefoxExecutable = '/usr/bin/firefox'
+ }
+ }
+ dap.configurations.javascript = dap.configurations.typescript
+ dap.configurations.javascriptreact = dap.configurations.typescript
+ dap.configurations.typescriptreact = dap.configurations.typescript
+
+ -- Javascript / Typescript (chromium)
+ -- If you prefer to use this adapter, comment the firefox one.
+ -- But to use this adapter, you must manually run one of these two, first:
+ -- * chromium --remote-debugging-port=9222 --user-data-dir=remote-profile
+ -- * google-chrome-stable --remote-debugging-port=9222 --user-data-dir=remote-profile
+ -- After starting the debugger, you must manually reload page to get all features.
+ -- dap.adapters.chrome = {
+ -- type = 'executable',
+ -- command = vim.fn.stdpath('data')..'/mason/bin/chrome-debug-adapter',
+ -- }
+ -- dap.configurations.typescript = {
+ -- {
+ -- name = 'Debug with Chromium',
+ -- type = "chrome",
+ -- request = "attach",
+ -- program = "${file}",
+ -- cwd = vim.fn.getcwd(),
+ -- sourceMaps = true,
+ -- protocol = "inspector",
+ -- port = 9222,
+ -- webRoot = "${workspaceFolder}"
+ -- }
+ -- }
+ -- dap.configurations.javascript = dap.configurations.typescript
+ -- dap.configurations.javascriptreact = dap.configurations.typescript
+ -- dap.configurations.typescriptreact = dap.configurations.typescript
+
+ -- PHP
+ dap.adapters.php = {
+ type = 'executable',
+ command = vim.fn.stdpath("data") .. '/mason/bin/php-debug-adapter',
+ }
+ dap.configurations.php = {
+ {
+ type = 'php',
+ request = 'launch',
+ name = 'Listen for Xdebug',
+ port = 9000
+ }
+ }
+
+ -- Shell
+ dap.adapters.bashdb = {
+ type = 'executable',
+ command = vim.fn.stdpath("data") .. '/mason/packages/bash-debug-adapter/bash-debug-adapter',
+ name = 'bashdb',
+ }
+ dap.configurations.sh = {
+ {
+ type = 'bashdb',
+ request = 'launch',
+ name = "Launch file",
+ showDebugOutput = true,
+ pathBashdb = vim.fn.stdpath("data") .. '/mason/packages/bash-debug-adapter/extension/bashdb_dir/bashdb',
+ pathBashdbLib = vim.fn.stdpath("data") .. '/mason/packages/bash-debug-adapter/extension/bashdb_dir',
+ trace = true,
+ file = "${file}",
+ program = "${file}",
+ cwd = '${workspaceFolder}',
+ pathCat = "cat",
+ pathBash = "/bin/bash",
+ pathMkfifo = "mkfifo",
+ pathPkill = "pkill",
+ args = {},
+ env = {},
+ terminalKind = "integrated",
+ }
+ }
+
+ -- Elixir
+ dap.adapters.mix_task = {
+ type = 'executable',
+ command = vim.fn.stdpath("data") .. '/mason/bin/elixir-ls-debugger',
+ args = {}
+ }
+ dap.configurations.elixir = {
+ {
+ type = "mix_task",
+ name = "mix test",
+ task = 'test',
+ taskArgs = { "--trace" },
+ request = "launch",
+ startApps = true, -- for Phoenix projects
+ projectDir = "${workspaceFolder}",
+ requireFiles = {
+ "test/**/test_helper.exs",
+ "test/**/*_test.exs"
+ }
+ },
+ }
+ end, -- of dap config
+ dependencies = {
+ "rcarriga/nvim-dap-ui",
+ "rcarriga/cmp-dap",
+ "jay-babu/mason-nvim-dap.nvim",
+ "jbyuki/one-small-step-for-vimkind",
+ "nvim-java/nvim-java",
+ },
+ },
+
+ -- nvim-dap-ui [dap ui]
+ -- https://github.com/mfussenegger/nvim-dap-ui
+ -- user interface for the debugger dap
+ {
+ "rcarriga/nvim-dap-ui",
+ dependencies = { "nvim-neotest/nvim-nio" },
+ opts = { floating = { border = "rounded" } },
+ config = function(_, opts)
+ local dap, dapui = require("dap"), require("dapui")
+ 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
+ dapui.setup(opts)
+ end,
+ },
+
+ -- cmp-dap [dap autocomplete]
+ -- https://github.com/mfussenegger/cmp-dap
+ -- Enables autocomplete for the debugger dap.
+ {
+ "rcarriga/cmp-dap",
+ dependencies = { "nvim-cmp" },
+ config = function()
+ require("cmp").setup.filetype(
+ { "dap-repl", "dapui_watches", "dapui_hover" },
+ {
+ sources = {
+ { name = "dap" },
+ },
+ }
+ )
+ end,
+ },
+
+ -- TESTING -----------------------------------------------------------------
+ -- Run tests inside of nvim [unit testing]
+ -- https://github.com/nvim-neotest/neotest
+ --
+ --
+ -- MANUAL:
+ -- -- Unit testing:
+ -- To tun an unit test you can run any of these commands:
+ --
+ -- :Neotest run -- Runs the nearest test to the cursor.
+ -- :Neotest stop -- Stop the nearest test to the cursor.
+ -- :Neotest run file -- Run all tests in the file.
+ --
+ -- -- E2e and Test Suite
+ -- Normally you will prefer to open your e2e framework GUI outside of nvim.
+ -- But you have the next commands in ../base/3-autocmds.lua:
+ --
+ -- :TestNodejs -- Run all tests for this nodejs project.
+ -- :TestNodejsE2e -- Run the e2e tests/suite for this nodejs project.
+ {
+ "nvim-neotest/neotest",
+ cmd = { "Neotest" },
+ dependencies = {
+ "sidlatau/neotest-dart",
+ "Issafalcon/neotest-dotnet",
+ "jfpedroza/neotest-elixir",
+ "nvim-neotest/neotest-go",
+ "rcasia/neotest-java",
+ "nvim-neotest/neotest-jest",
+ "olimorris/neotest-phpunit",
+ "nvim-neotest/neotest-python",
+ "rouge8/neotest-rust",
+ "lawrence-laz/neotest-zig",
+ },
+ opts = function()
+ return {
+ -- your neotest config here
+ adapters = {
+ require("neotest-dart"),
+ require("neotest-dotnet"),
+ require("neotest-elixir"),
+ require("neotest-go"),
+ require("neotest-java"),
+ require("neotest-jest"),
+ require("neotest-phpunit"),
+ require("neotest-python"),
+ require("neotest-rust"),
+ require("neotest-zig"),
+ },
+ }
+ end,
+ config = function(_, opts)
+ -- get neotest namespace (api call creates or returns namespace)
+ 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,
+ },
+ }, neotest_ns)
+ require("neotest").setup(opts)
+ end,
+ },
+
+ -- Shows a float panel with the [code coverage]
+ -- https://github.com/andythigpen/nvim-coverage
+ --
+ -- Your project must generate coverage/lcov.info for this to work.
+ --
+ -- On jest, make sure your packages.json file has this:
+ -- "tests": "jest --coverage"
+ --
+ -- If you use other framework or language, refer to nvim-coverage docs:
+ -- https://github.com/andythigpen/nvim-coverage/blob/main/doc/nvim-coverage.txt
+ {
+ "zeioth/nvim-coverage", -- Our fork until all our PRs are merged.
+ cmd = {
+ "Coverage",
+ "CoverageLoad",
+ "CoverageLoadLcov",
+ "CoverageShow",
+ "CoverageHide",
+ "CoverageToggle",
+ "CoverageClear",
+ "CoverageSummary",
+ },
+ dependencies = { "nvim-lua/plenary.nvim" },
+ opts = {
+ summary = {
+ min_coverage = 80.0, -- passes if higher than
+ },
+ },
+ config = function(_, opts) require("coverage").setup(opts) end,
+ },
+
+ -- LANGUAGE IMPROVEMENTS ----------------------------------------------------
+ -- guttentags_plus [auto generate C/C++ tags]
+ -- https://github.com/skywind3000/gutentags_plus
+ -- This plugin is necessary for using <C-]> (go to ctag).
+ {
+ "skywind3000/gutentags_plus",
+ ft = { "c", "cpp" },
+ dependencies = { "ludovicchabant/vim-gutentags" },
+ config = function()
+ -- NOTE: On vimplugins we use config instead of opts.
+ vim.g.gutentags_plus_nomap = 1
+ vim.g.gutentags_resolve_symlinks = 1
+ vim.g.gutentags_cache_dir = vim.fn.stdpath "cache" .. "/tags"
+ vim.api.nvim_create_autocmd("FileType", {
+ desc = "Auto generate C/C++ tags",
+ callback = function()
+ local is_c = vim.bo.filetype == "c" or vim.bo.filetype == "cpp"
+ if is_c then vim.g.gutentags_enabled = 1
+ else vim.g.gutentags_enabled = 0 end
+ end,
+ })
+ end,
+ },
+
+} -- end of return
@@ -1,11 +1,11 @@
[colors]
background = ${xrdb:background}
-background-alt = ${xrdb:color7}
+background-alt = ${xrdb:color8}
foreground = ${xrdb:foreground}
foreground-alt = ${xrdb:color0}
primary = ${xrdb:color1}
secondary = ${xrdb:color11}
-alert = ${xrdb:color3}
+alert = ${xrdb:color11}
[bar/top]
width = 100%
@@ -104,8 +104,8 @@ label-visible-padding = ${self.label-focused-padding}
; urgent = Workspace with urgency hint set
label-urgent = %index%
label-urgent-background = ${colors.alert}
-label-urgent-foreground = ${colors.foreground-alt}
-label-urgent-underline = ${colors.foreground}
+label-urgent-foreground = ${colors.background}
+label-urgent-underline = ${colors.alert}
label-urgent-padding = 1
[module/mail]
@@ -6,43 +6,43 @@ set selection-clipboard "clipboard"
{{- if eq .theme_variant "dark" }}
-set default-fg "#CAD3F5"
-set default-bg "#24273A"
-
-set completion-bg "#363A4F"
-set completion-fg "#CAD3F5"
-set completion-highlight-bg "#575268"
-set completion-highlight-fg "#CAD3F5"
-set completion-group-bg "#363A4F"
-set completion-group-fg "#8AADF4"
-
-set statusbar-fg "#CAD3F5"
-set statusbar-bg "#363A4F"
-
-set notification-bg "#363A4F"
-set notification-fg "#CAD3F5"
-set notification-error-bg "#363A4F"
-set notification-error-fg "#ED8796"
-set notification-warning-bg "#363A4F"
-set notification-warning-fg "#FAE3B0"
-
-set inputbar-fg "#CAD3F5"
-set inputbar-bg "#363A4F"
-
-set recolor-lightcolor "#24273A"
-set recolor-darkcolor "#CAD3F5"
-
-set index-fg "#CAD3F5"
-set index-bg "#24273A"
-set index-active-fg "#CAD3F5"
-set index-active-bg "#363A4F"
-
-set render-loading-bg "#24273A"
-set render-loading-fg "#CAD3F5"
-
-set highlight-color "#575268"
-set highlight-fg "#F5BDE6"
-set highlight-active-color "#F5BDE6"
+set default-fg "#d3c6aa"
+set default-bg "#272e33"
+
+set completion-bg "#2e383c"
+set completion-fg "#d3c6aa"
+set completion-highlight-bg "#dbbc7f"
+set completion-highlight-fg "#d3c6aa"
+set completion-group-bg "#2e383c"
+set completion-group-fg "#7fbbb3"
+
+set statusbar-fg "#d3c6aa"
+set statusbar-bg "#2e383c"
+
+set notification-bg "#2e383c"
+set notification-fg "#d3c6aa"
+set notification-error-bg "#2e383c"
+set notification-error-fg "#e67e80"
+set notification-warning-bg "#2e383c"
+set notification-warning-fg "#dbbc7f"
+
+set inputbar-fg "#d3c6aa"
+set inputbar-bg "#2e383c"
+
+set recolor-lightcolor "#272e33"
+set recolor-darkcolor "#d3c6aa"
+
+set index-fg "#d3c6aa"
+set index-bg "#272e33"
+set index-active-fg "#d3c6aa"
+set index-active-bg "#2e383c"
+
+set render-loading-bg "#272e33"
+set render-loading-fg "#d3c6aa"
+
+set highlight-color "#dbbc7f"
+set highlight-fg "#d699b6"
+set highlight-active-color "#d699b6"
{{- end }}
{{- if eq .theme_variant "light" }}
set default-fg "#4C4F69"
@@ -50,7 +50,7 @@ set default-bg "#EFF1F5"
set completion-bg "#CCD0DA"
set completion-fg "#4C4F69"
-set completion-highlight-bg "#575268"
+set completion-highlight-bg "#dbbc7f"
set completion-highlight-fg "#4C4F69"
set completion-group-bg "#CCD0DA"
set completion-group-fg "#1E66F5"
@@ -79,7 +79,7 @@ set index-active-bg "#CCD0DA"
set render-loading-bg "#EFF1F5"
set render-loading-fg "#4C4F69"
-set highlight-color "#575268"
+set highlight-color "#dbbc7f"
set highlight-fg "#EA76CB"
set highlight-active-color "#EA76CB"
{{- end }}
@@ -1,13 +1,13 @@
# Theming
{{- if eq .theme_variant "dark" }}
# https://github.com/catppuccin/zsh-syntax-highlighting
-source ~/.config/zsh/themes/catppuccin-macchiato.zsh
-export BAT_THEME="Catppuccin-macchiato"
+source ~/.config/zsh/themes/everforest-hard-dark.zsh
+export BAT_THEME="ansi"
{{- end }}
{{- if eq .theme_variant "light" }}
# https://github.com/catppuccin/zsh-syntax-highlighting
-source ~/.config/zsh/themes/catppuccin-latte.zsh
-export BAT_THEME="Catppuccin-latte"
+source ~/.config/zsh/themes/everforest-soft-light.zsh
+export BAT_THEME="ansi"
{{- end }}
# Remove older command from the history if a duplicate is to be added.
@@ -33,11 +33,10 @@ zstyle ':zim:termtitle:precmd' format '%1~'
# Customize the style that the suggestions are shown with.
# Set what highlighters will be used.
# See https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters.md
-ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets)
+ZSH_HIGHLIGHT_HIGHLIGHTERS=(main cursor)
# Customize the main highlighter styles.
# See https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters/main.md#how-to-tweak-it
-#typeset -A ZSH_HIGHLIGHT_STYLES
-#ZSH_HIGHLIGHT_STYLES[comment]='fg=242'
+typeset -gA ZSH_HIGHLIGHT_STYLES
# XDG variables
export XDG_DATA_HOME="$HOME/.local/share"
@@ -122,11 +121,13 @@ export PATH="$PATH:$CACHE/yay/distrobox/pkg/distrobox/usr/bin"
export PATH="$PATH:$XDG_DATA_HOME/cargo/bin"
export PATH="$PATH:$HOME/.radicle/bin"
export PATH="$HOME/.local/bin:$PATH"
+export PATH="$PATH:/usr/lib/kf6"
+export PATH="$PATH:/usr/lib/kf5"
# Additional preferences
export LANG=en_GB.UTF-8
-export EDITOR='emacsclient -c'
-export VISUAL='emacsclient -c'
+export EDITOR='nvim'
+export VISUAL='nvim'
export _JAVA_AWT_WM_NONREPARENTING=1
export MANPAGER="nvim +Man!"
export COLUMNS=80
@@ -163,6 +164,9 @@ source /usr/share/z/z.sh
source /usr/share/fzf/key-bindings.zsh
source /usr/share/fzf/completion.zsh
+# Completions for git extras
+source /usr/share/doc/git-extras/git-extras-completion.zsh
+
# Ranger conf
export RANGER_LOAD_DEFAULT_RC=false
@@ -177,7 +181,6 @@ alias u="linx-client"
alias clip="xclip -selection clipboard"
alias tmp="cd $(mktemp -d) && export TEMP=$(pwd)"
alias send="rsync -amzzP"
-alias tree="eza --tree"
alias bat="bat -n --tabs 2"
alias mov="joshuto ~/Bulk/Media/Movies"
alias tv="joshuto ~/Bulk/Media/TV\ Shows"
@@ -194,6 +197,7 @@ alias ac="aicommits"
alias tc="turbocommit"
alias ai="sgpt"
alias k="klog"
+alias ls="lsd"
# Blog-related aliases
alias secluded="cd ~/repos/personal/secluded && ./gen"
@@ -13,6 +13,7 @@ if [[ -n $WAYLAND_DISPLAY ]]; then
hyprctl -i 0 dispatch exec -- "xfsettingsd"
hyprctl -i 0 dispatch exec -- "dbus-update-activation-environment --all"
hyprctl -i 0 dispatch exec -- "telegram-desktop"
+ hyprctl -i 0 dispatch exec -- "kdeconnect-indicator"
{{- if eq .chezmoi.hostname "angmar" }}
hyprctl -i 0 dispatch exec -- "caddy start --adapter caddyfile --config ~/Bulk/Media/Caddyfile"
hyprctl -i 0 dispatch exec -- "firefox-developer-edition"
@@ -37,6 +38,7 @@ else
i3-msg exec "xrdb -load ~/.Xresources"
i3-msg exec "xfsettingsd"
i3-msg exec "dbus-update-activation-environment --all"
+ i3-msg exec "kdeconnect-indicator"
{{- if eq .chezmoi.hostname "angmar" }}
i3-msg exec "caddy start --adapter caddyfile --config ~/Bulk/Media/Caddyfile"
i3-msg workspace 7
@@ -3,6 +3,9 @@
sed -i 's/light/dark/g' ~/.config/chezmoi/chezmoi.toml
chezmoi apply
xfconf-query -c xsettings -p /Net/ThemeName -s "Everforest-Dark"
+xfconf-query -c xsettings -p /Net/IconThemeName -s "Everforest-Dark"
+gsettings set org.gnome.desktop.interface gtk-theme "Everforest-Dark"
+gsettings set org.gnome.desktop.interface icon-theme "Everforest-Dark"
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'
xrdb -load ~/.Xresources
"$XDG_CONFIG_HOME/emacs/bin/doom" sync
@@ -23,6 +26,6 @@ else
fi
unlink ~/.wallpaper.png
-ln -s ~/Pictures/walls/everforest-dark.png ~/.wallpaper.png
+ln -s ~/Pictures/walls/everforest-hard-dark.png ~/.wallpaper.png
feh --bg-scale ~/.wallpaper.png
notify-send "Theme switch complete"
@@ -3,6 +3,9 @@
sed -i 's/dark/light/g' ~/.config/chezmoi/chezmoi.toml
chezmoi apply
xfconf-query -c xsettings -p /Net/ThemeName -s "Everforest-Light-Soft"
+xfconf-query -c xsettings -p /Net/IconThemeName -s "Everforest-Light"
+gsettings set org.gnome.desktop.interface gtk-theme "Everforest-Light-Soft"
+gsettings set org.gnome.desktop.interface icon-theme "Everforest-Light"
gsettings set org.gnome.desktop.interface color-scheme 'prefer-light'
xrdb -load ~/.Xresources
"$XDG_CONFIG_HOME/emacs/bin/doom" sync
@@ -23,6 +26,6 @@ else
fi
unlink ~/.wallpaper.png
-ln -s ~/Pictures/walls/everforest-light.png ~/.wallpaper.png
+ln -s ~/Pictures/walls/everforest-soft-light.png ~/.wallpaper.png
feh --bg-scale ~/.wallpaper.png
notify-send "Theme switch complete"
@@ -1,43 +1,42 @@
-----BEGIN AGE ENCRYPTED FILE-----
-YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEhBV2NqUSBBM0FHalZP
-VTZOR1Q0THYrZmZwaER2ZkpCK0RNY0thNmtwVXdzb1ppSWFpMgpJRkdYVVVCSEN0
-Y1dsNkRDWVAvUlc1R3M1dmJodFRrNk9SV3B1azhGTFZRCi0+IHBpdi1wMjU2IHBE
-YXpSZyBBcFZLdFJpM2pmaGQrVWZ1MkdNZWlqeVQ2RU90Yk9IRW4vK2V5RnBrWTJB
-RQp3QUR0aFBvWERzdHJlTEIvTHVEb2wzOERlS0Izdy9UcU81SnVmVlVsQXZJCi0+
-IEtUdVkyLWdyZWFzZSBFJ2kgPSJ+ZmYxIEFyfEY1CjZaN29VelNjN0Mzem1lRVAv
-NTVBVFJLTFd5V1hqVGZtQmovbUJSUXFrWXpUdXZ6WFZGa2JrN1kya1ZrTnhhSTcK
-djdwR3NtUmdiamw2SE1nZEFrWG5XU3dtUGFPWnVBCi0tLSBGNUI4U094TmxMTFlW
-OXVac3FmcGFCQ0JnTTc0V3lvcE9mcFFxZkI1SWI0CvCj9INWMTXsV7Qjkwx3qDi5
-TYMUxhSt4tLIxnqrlCiMu/u7yYkXh+Xb/GRng3Nlptp357mRkXn/sM7Rtm2qeki+
-zX9MUiFOUzX+FsqKQ3rOfU9AIBQjkC8Y0ZbTjn17c+/itoh4gV+boCQsdVcTzLLM
-nQeByWkLnxjq0B97brgCCXUuPP7Lzu88kOzCp+I/KmVgSNj1o2LSWFM6B7Ptofgb
-o/L25xjXSM0XYqnZeAeNZAWfkvpJ/arXUtzMEVSqGMWSvBZQ51On3zrKDkQThUc1
-2bIVs+FVfYJQCyhuUweMbWqyyU+Ru4HbeH4WA9pTqhHsUJi1ZU5wAlyX7ezUyLZU
-y39CEU1wLamNzVeZwbhQv9DbrmHMnOl9tHpzX518hA50FGt9294TSzB2CcPSAjYA
-SKfqZgOxdF8DdJuqBj0O5rJ9tEXPHkUI+TkyOcnpln8yVyUHM/wpOMpgsS8bfDPL
-8o/J7wg56FfHsy1F72QyhMQsyquPWCHtmCXncHVWwlXE5pxeCazdcn4TVSPXs+Fq
-yLYepyYhodQNNBJvfUvRN7BUkf2OTAZQGI8VMo9nibdpnfRxZrcp7wJcxJ06va/C
-JYy2gkKbKa98pUr7ToCqaxDiPe6r8MIuYJ+MaW3imvEF/4b+DO3BrYBdPEaA/uH4
-EB8X20Eq5e3h37iDZAh6l9I++sJlyTRD+rjd9z3wc8bP7mhsbGsI+OzVK82J8ha2
-yBLo9XLpt3m691RDxEeUtugDpunEPhf6Woak8ErwUZcJ0rMQ9khLstzCFoehKeqV
-Ffh8yXz8D/ZPWxY1OdxzVQ8Bd3JxYZlmjRTAbQL/yLZg0PBqFr0Ny2aBxfoGYLMB
-NpzwX4uUCPbyK2g3tNHafL1YDIitEEiobYVnnhVIbJQqMhS/gsVW2daMNvJ/3KZu
-1K3azW4t305/ryddRUBZ/ezJx/mf1Tr9xxnb9aj3MsvyhjbExFjUkx8/vEtnDZuA
-9IPlsD0+ydoEA+IGJqepox3Sabl6x9e3ya2maa+1TF2K3h4mVQNp09yOrBhl1Eyr
-V3eMWZe58nbFOdn8Aq99Ru0RkMesvvFAsAsKcwwuemLFNzdrl89Juuhr0dzXtMZu
-GIX09i5bL60rZXl6RQx6rWoT28ir9yaYHZYqoEXlm4IZOEo0Bc3yKWATw0chpdvX
-qlmz28gudJOBfvgfybC4SO7rD2g5vD+YRrhRQ7YOqQAuq6BcnSfUYilLC2PoBSCx
-HipZ3cZvQSoqZ1D3R7mSZI1Rh9O6GZlU6UgXxrK0RBAqPL62APN8nlMyisXlt7KM
-zwwDozt35qXSVf0ZgiDUTRwlfsUn6W+aJOsZasnLdIJDN0Y6nz4092brzMoz1ZIy
-xAM9Gt772DDmOsgb2pDZ8YAQzO+3/U1/v/ikF/g9DZxLN+xQbT9zGJ1yrScvKS04
-7kny+e2cB6ye7iUafCsM0HzKg0b+NFyHqADeWO1MxJQYO8VjK3wbedbJ6pJ+9MRj
-rjRt1ZwD2dCYphynYhpcy2CtImR4ngOMqoRtQEFTXcWafig1itkOnqYmLsy5dEH9
-YuOFeIyme9vwVvrh4WcOeSVnZOVExvEiKAkRageYCmL51BR+w92nuXBwzvhP6RM5
-KILstftZh8auNuEmDw9hK+FbOOSjJNSkkI8DKw5rTyvlVpGXxf7NYHMeYRkDFQfr
-C3be+qzGocb9GOcFGiMp4W48xkUMwrn2YTaWACFawOEdtlyfUPIjFhEQCdu4CZ0p
-lERNyo91DpcFLA6YqYUusJdrDd1988wzFURBMkas6tPCTZuuzj1lcvqhW/g2kKOT
-PrAx4ftx7qbdWzoZ+VMY9U/R9knnO+xnQ8kmp+zAcc08N6ycNcrGGsJF/LC49cpA
-m/282hpCQbUCgRxch+2uNH7IK0uos/b4Ee6ubrxNYXCSZKqtIYr4Vq8PjNumdQq7
-bSTVWNXGT54FmKhmSglMje8ANDGQM+aAiNbbip+GOiQAg6h7elFhY0uuUbb8k0ZV
-XRlXO2pKlUaTY7XCdh28ZimCnfsinjRepNkgnR8YR2ETsPTXVkJ/SU8+KPRe
+YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IEhBV2NqUSBBOSs0ZzhD
+d3RyKzZYekU5ckRNUDVzVVNtc2FpeEx5a0FsNEJGaXBvakVzUApndWMwSEFkSTYz
+SUdRL3JMZnFwbGR6dFczT2tVd050VitUWkpZWlh6cVlBCi0+IHBpdi1wMjU2IHBE
+YXpSZyBBa0RkZi9uZ1ZxUmdrZEpKWEhLZGQ4SkdGVTBteDY4SzRRRUY2aStIZllP
+Vgp4cDZjenZReG1ubHNRdVdPWWhxM1NoUlBwQW5EZmhmeFdqdTdUWFBNKzNvCi0+
+IDd6aTBCPUEtZ3JlYXNlIHIqKW5vSicgS1pITGBSTSBZPyA/Ci9JMEw5YXhzQVRE
+ci9HZUpQUG0xSUdTQkJCQmd2M2ppeWFpTVVTc3JnSkVYd1h1NWhVaTcvcXRTQWlo
+eUJXN1MKZU9aL2IwUmNGR2I2NmRyd1hSNjhKdWJxY0EKLS0tIDJSUUx3MTRhL1Bo
+bVJaUUs0UTNaYkd6RE5GVTR4MUcwcS9GVERZVnllUXMKjy5S2mub3DsSJyQZJ3nG
+uqjR0xoW7xn/gd6tuwNunc6cCtpspp4QU//lNnARl3urpzTlLPbisadhNBKG7+i4
+Y65e6J7Zh/UyBf09VNCVnA4cV2jCB/jPARwXZyxAjyFzCeP6ze7Qsca9dzx6EazA
+I1ocbPPDdNOHzcwq0nGec4N5H9DBTOK9sAveNsXw1e3KMy2BO/WO27iEIFthDkPR
+ve4zQZogbhNfDH3oP98roYVBOufn7u+iV+Kye60MyAjorF3BG+BqViLm9KPJQjO+
+a4yCcxNitdBsN/SJ+e7pPNtfXbdzNgmjRyHgjOQMa4D/dCwbNSawFbQtWOTXh5KG
+kABrOEBsiSYH4pGSkpRCUUXmDwbtVpRRs75CoGb2b3mpmYmC3lDRweQ9iv7s0S18
+hi5piJO2PFx8xDUGqhJ1/WqCATs60Lsv99hgn6WolmJISeSqmUa1Y7GAgmVwCs3K
+GsiYZ1olzXgDAaAv3N//no9kGOnoJ3BnJl3fezuzljmKYLFtOfGNxwmOamrOeZfo
+wMKKZrDM2daoy2HkhbFCeXzqDNbZ0HQk8IFo+tvFbQqx3rijD0/YKiTgCEgIscyh
+a9z7DQ8AhpyaD3QX4FShi3mfnB89Apa87n7GdTWRhSqtH1GGd4l2n/kNm02E9B5q
+o0Q43y3xo8lTm3xbN4DX4J9kFQC0H8zzcvqkmZT7OJMb2YypnKMnm1Dl/0OImQVG
+jIhx7Dc2EpDlf2MBuQ+AUYseUAp18MdT1HlpOMzjrd15+k4vyBkXrWiFUudNf3+Q
+YGN3aHGA/TYtfbjKAGFhaMR87RlC4jKa9aL2FN8iiys0MAkl+WoWh/5P7hnLkZln
+WTAaayUxTqm7GhDjxR8uK+kqkbJMvyOvXhEL79PnkkO58lZDM/CiNSMF+Z5YPT1m
+R6K+p0mZnszn2zf+dgxVnmlYl09nEGW0PX8sdDQ9BG83jdQl27/q0pb6T8lPdbBB
+UbNarEaj2QGLrE/v0ZAPXf4lnMoOieKDvN8kCr7+gj7Agtn0pIZJydNQuokP4UMj
+fFTqzZgpec3w2Tmne63wcOI8ZhpP2itfQlU8Bee/qrQrZd4mJgs89qF2zRdWiw9h
+n60mOZIi+1j5QG2HdZzU9fzOgi7EulRj4VRf1Z3hNUehqUQYtRSEgGLyoSExO9TB
+X+2LBJOqs0tTUTT8bdzPXJ+XlmmAB951g9nKPFWa4VaZQfGk5iYrlYT20Ontl09a
+yiTbYTWLdl+AB6yJBM5P6guYpjzg3wvtcvGkuW+UsDI70GsyauwTo+OHN5UeTloZ
+ZYVdyOHnT7WcrzanrXylb+wLP9Y5wDj+0JL2qdZpAzNUA/PNBVJzmY8qDltq/f7D
+iUHUYEzSNJArwGrYQUd8Mubx8Rt1PUmWLJBcv6NV9hyClq6WiuXUmpaOoMjNpTiA
+2pfzb2svjrdC9anFah1k7KDhrPkzhB5ld/o4b5mnqWGtRSVIETSZPr0wXsD2N05N
+fe5BeE3+5YOd6xFj3Nt7Xa1ZHfgR1Gt4Nqhlx9MpNpmK7EqLIDPeyfd5QdK1kHD2
+RXGe44aRs3qI7JqrDjbHq3lJCfhjm4PR1uDZa7tGfQ23R/MUHhIumpAEhJWJ3BKB
+se7hb+2EGTaHNII3BQogpVPg8X/qzZ1sHMiy0mLcg/Mv64+1FELczmjSAUKnDPj0
+cRuJEkr1/CBMiQc28/PIj6PVeNB2J8d+wWa5Yoy0mgo2lAm+MznKdTP4OSKQtixt
+sedAX/RR9tHgZSYvNDIbt6XqKkV3ROFxuaaRpvyXKOG45Rcg2D1DjijOLrBHmIdu
+FUCsh1VY10D8D0h8sEib0/wr2BoEpNv7eEse4QVI78GABrDUG3awBHa3XewY92mg
+x15Q731cNt88PmOxLIl56hfXr+VJuMAffOYvyQ8ZqsdmmOzpJmojc1uFuavUBiV/
+WUSwjlRyPb27vpr5eATwY6ZjJwpJ5tfbid8KFWubuQ==
-----END AGE ENCRYPTED FILE-----