From cac3518985d03de0c72e6766fd29c407254416ca Mon Sep 17 00:00:00 2001 From: Arjun Patel Date: Fri, 3 Feb 2023 05:53:00 -0600 Subject: [PATCH] adding initial base config from astrovim --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 9 + .luacheckrc | 21 + .stylua.toml | 7 + LICENSE | 674 +++++++++ config.ld | 10 + init.lua | 21 + lua/configs/Comment.lua | 16 + lua/configs/aerial.lua | 25 + lua/configs/alpha.lua | 36 + lua/configs/autopairs.lua | 28 + lua/configs/better_escape.lua | 1 + lua/configs/bufferline.lua | 36 + lua/configs/cmp.lua | 92 ++ lua/configs/colorizer.lua | 3 + lua/configs/dap.lua | 3 + lua/configs/dapui.lua | 5 + lua/configs/dressing.lua | 10 + lua/configs/gitsigns.lua | 10 + lua/configs/heirline.lua | 309 +++++ lua/configs/indent-line.lua | 45 + lua/configs/indent-o-matic.lua | 3 + lua/configs/lspconfig.lua | 13 + lua/configs/lspkind.lua | 23 + lua/configs/luasnip.lua | 17 + lua/configs/mason-lspconfig.lua | 6 + lua/configs/mason-null-ls.lua | 3 + lua/configs/mason-nvim-dap.lua | 3 + lua/configs/mason.lua | 13 + lua/configs/neo-tree.lua | 67 + lua/configs/notify.lua | 3 + lua/configs/null-ls.lua | 1 + lua/configs/nvim-web-devicons.lua | 15 + lua/configs/server-settings/jsonls.lua | 8 + lua/configs/server-settings/sumneko_lua.lua | 16 + lua/configs/session_manager.lua | 1 + lua/configs/smart-splits.lua | 9 + lua/configs/telescope.lua | 39 + lua/configs/toggleterm.lua | 13 + lua/configs/treesitter.lua | 19 + lua/configs/which-key-register.lua | 55 + lua/configs/which-key.lua | 11 + lua/configs/window-picker.lua | 4 + lua/core/autocmds.lua | 213 +++ lua/core/bootstrap.lua | 4 + lua/core/diagnostics.lua | 43 + lua/core/icons/nerd_font.lua | 46 + lua/core/icons/text.lua | 38 + lua/core/mappings.lua | 317 +++++ lua/core/options.lua | 72 + lua/core/plugins.lua | 375 +++++ lua/core/utils/git.lua | 157 +++ lua/core/utils/init.lua | 606 ++++++++ lua/core/utils/lsp.lua | 243 ++++ lua/core/utils/mason.lua | 95 ++ lua/core/utils/status.lua | 1216 +++++++++++++++++ lua/core/utils/ui.lua | 188 +++ lua/core/utils/updater.lua | 296 ++++ lua/default_theme/base.lua | 86 ++ lua/default_theme/colors.lua | 82 ++ lua/default_theme/init.lua | 68 + lua/default_theme/lsp.lua | 26 + lua/default_theme/plugins/aerial.lua | 31 + lua/default_theme/plugins/beacon.lua | 1 + lua/default_theme/plugins/bufferline.lua | 14 + lua/default_theme/plugins/cmp.lua | 34 + lua/default_theme/plugins/dapui.lua | 29 + lua/default_theme/plugins/dashboard.lua | 6 + lua/default_theme/plugins/gitsigns.lua | 7 + lua/default_theme/plugins/highlighturl.lua | 1 + lua/default_theme/plugins/hop.lua | 6 + .../plugins/indent_blankline.lua | 7 + lua/default_theme/plugins/lightspeed.lua | 14 + lua/default_theme/plugins/neo-tree.lua | 15 + lua/default_theme/plugins/notify.lua | 25 + lua/default_theme/plugins/nvim-tree.lua | 19 + .../plugins/nvim-web-devicons.lua | 34 + lua/default_theme/plugins/rainbow.lua | 9 + lua/default_theme/plugins/symbols_outline.lua | 1 + lua/default_theme/plugins/telescope.lua | 57 + lua/default_theme/plugins/treesitter.lua | 63 + lua/default_theme/plugins/vimwiki.lua | 14 + lua/default_theme/plugins/which-key.lua | 5 + lua/user_example/init.lua | 363 +++++ pack/github/start/copilot.vim | 1 + packer_snapshot | 1 + 86 files changed, 6631 insertions(+) create mode 100644 .DS_Store create mode 100644 .gitignore create mode 100644 .luacheckrc create mode 100644 .stylua.toml create mode 100644 LICENSE create mode 100644 config.ld create mode 100644 init.lua create mode 100644 lua/configs/Comment.lua create mode 100644 lua/configs/aerial.lua create mode 100644 lua/configs/alpha.lua create mode 100644 lua/configs/autopairs.lua create mode 100644 lua/configs/better_escape.lua create mode 100644 lua/configs/bufferline.lua create mode 100644 lua/configs/cmp.lua create mode 100644 lua/configs/colorizer.lua create mode 100644 lua/configs/dap.lua create mode 100644 lua/configs/dapui.lua create mode 100644 lua/configs/dressing.lua create mode 100644 lua/configs/gitsigns.lua create mode 100644 lua/configs/heirline.lua create mode 100644 lua/configs/indent-line.lua create mode 100644 lua/configs/indent-o-matic.lua create mode 100644 lua/configs/lspconfig.lua create mode 100644 lua/configs/lspkind.lua create mode 100644 lua/configs/luasnip.lua create mode 100644 lua/configs/mason-lspconfig.lua create mode 100644 lua/configs/mason-null-ls.lua create mode 100644 lua/configs/mason-nvim-dap.lua create mode 100644 lua/configs/mason.lua create mode 100644 lua/configs/neo-tree.lua create mode 100644 lua/configs/notify.lua create mode 100644 lua/configs/null-ls.lua create mode 100644 lua/configs/nvim-web-devicons.lua create mode 100644 lua/configs/server-settings/jsonls.lua create mode 100644 lua/configs/server-settings/sumneko_lua.lua create mode 100644 lua/configs/session_manager.lua create mode 100644 lua/configs/smart-splits.lua create mode 100644 lua/configs/telescope.lua create mode 100644 lua/configs/toggleterm.lua create mode 100644 lua/configs/treesitter.lua create mode 100644 lua/configs/which-key-register.lua create mode 100644 lua/configs/which-key.lua create mode 100644 lua/configs/window-picker.lua create mode 100644 lua/core/autocmds.lua create mode 100644 lua/core/bootstrap.lua create mode 100644 lua/core/diagnostics.lua create mode 100644 lua/core/icons/nerd_font.lua create mode 100644 lua/core/icons/text.lua create mode 100644 lua/core/mappings.lua create mode 100644 lua/core/options.lua create mode 100644 lua/core/plugins.lua create mode 100644 lua/core/utils/git.lua create mode 100644 lua/core/utils/init.lua create mode 100644 lua/core/utils/lsp.lua create mode 100644 lua/core/utils/mason.lua create mode 100644 lua/core/utils/status.lua create mode 100644 lua/core/utils/ui.lua create mode 100644 lua/core/utils/updater.lua create mode 100644 lua/default_theme/base.lua create mode 100644 lua/default_theme/colors.lua create mode 100644 lua/default_theme/init.lua create mode 100644 lua/default_theme/lsp.lua create mode 100644 lua/default_theme/plugins/aerial.lua create mode 100644 lua/default_theme/plugins/beacon.lua create mode 100644 lua/default_theme/plugins/bufferline.lua create mode 100644 lua/default_theme/plugins/cmp.lua create mode 100644 lua/default_theme/plugins/dapui.lua create mode 100644 lua/default_theme/plugins/dashboard.lua create mode 100644 lua/default_theme/plugins/gitsigns.lua create mode 100644 lua/default_theme/plugins/highlighturl.lua create mode 100644 lua/default_theme/plugins/hop.lua create mode 100644 lua/default_theme/plugins/indent_blankline.lua create mode 100644 lua/default_theme/plugins/lightspeed.lua create mode 100644 lua/default_theme/plugins/neo-tree.lua create mode 100644 lua/default_theme/plugins/notify.lua create mode 100644 lua/default_theme/plugins/nvim-tree.lua create mode 100644 lua/default_theme/plugins/nvim-web-devicons.lua create mode 100644 lua/default_theme/plugins/rainbow.lua create mode 100644 lua/default_theme/plugins/symbols_outline.lua create mode 100644 lua/default_theme/plugins/telescope.lua create mode 100644 lua/default_theme/plugins/treesitter.lua create mode 100644 lua/default_theme/plugins/vimwiki.lua create mode 100644 lua/default_theme/plugins/which-key.lua create mode 100644 lua/user_example/init.lua create mode 160000 pack/github/start/copilot.vim create mode 100644 packer_snapshot diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d4228280e62f4e0a0d9279b57e539280b52c855e GIT binary patch literal 6148 zcmeHK%}T>S5T2<8BMSEDac|;9=o`cmpP)xC5({miAq89T;2|d;!AJ206c0XvN1w!R zcE*|?>rq5!VD{V0&+g_+$Yh9!N9)OuXh1{>RIs;);R_MJXh(Wx5hu$Ui|KHDRTj%m zq#J%K1M=+pbV^g2)2i|Oj_=OvzM{;sd{O4GCAV*{*Z0p)XHEa)TmN!adpAx3Qfc>N zUz*XH^2Y9T^U#f`pW)?jb#d?*&(K<@C_hiKJ*sgYPUSo<&VV!E4Ez@cP_spneMKLg z0cXG&*f1d9hX55!4J*a?>A(ZTSX^pY zDQY^gH6Ls{vvnvOcgOl6hLiuq7Q&aFwU4bV%dh{RQjn-ol9DMqZ6;v;Aj*n>=fsbQrE3&ei}A`Lz`13${ZJI}#N AX#fBK literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4678955 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +!colors/default_theme.lua +colors/* +docs +ginit.vim +lua/packer_compiled.lua +lua/user +plugin +ftplugin +spell diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 0000000..809581e --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,21 @@ +-- Global objects +globals = { + "PACKER_BOOTSTRAP", + "astronvim", + "astronvim_installation", + "vim", + "bit", + "C", + "packer_plugins", +} + +-- Rerun tests only if their modification time changed +cache = true + +-- Don't report unused self arguments of methods +self = false + +ignore = { + "631", -- max_line_length + "212/_.*", -- unused argument, for vars with "_" prefix +} diff --git a/.stylua.toml b/.stylua.toml new file mode 100644 index 0000000..bfcffff --- /dev/null +++ b/.stylua.toml @@ -0,0 +1,7 @@ +column_width = 120 +line_endings = "Unix" +indent_type = "Spaces" +indent_width = 2 +quote_style = "AutoPreferDouble" +call_parentheses = "None" +collapse_simple_statement = "Always" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/config.ld b/config.ld new file mode 100644 index 0000000..0bb9d28 --- /dev/null +++ b/config.ld @@ -0,0 +1,10 @@ +project='AstroNvim' +title='AstroNvim API' +description='Documentation of AstroNvim\'s core API' +format = 'markdown' +file='lua' +dir='docs' +no_space_before_args=true +examples = { + 'lua/user_example/init.lua' +} diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..2bf8f14 --- /dev/null +++ b/init.lua @@ -0,0 +1,21 @@ +local impatient_ok, impatient = pcall(require, "impatient") +if impatient_ok then impatient.enable_profile() end + +for _, source in ipairs { + "core.utils", + "core.options", + "core.bootstrap", + "core.diagnostics", + "core.autocmds", + "core.mappings", + "configs.which-key-register", +} do + local status_ok, fault = pcall(require, source) + if not status_ok then vim.api.nvim_err_writeln("Failed to load " .. source .. "\n\n" .. fault) end +end + +astronvim.conditional_func(astronvim.user_plugin_opts("polish", nil, false)) + +if vim.fn.has "nvim-0.8" ~= 1 or vim.version().prerelease then + vim.schedule(function() astronvim.notify("Unsupported Neovim Version! Please check the requirements", "error") end) +end diff --git a/lua/configs/Comment.lua b/lua/configs/Comment.lua new file mode 100644 index 0000000..6521d72 --- /dev/null +++ b/lua/configs/Comment.lua @@ -0,0 +1,16 @@ +local utils = require "Comment.utils" +require("Comment").setup(astronvim.user_plugin_opts("plugins.Comment", { + pre_hook = function(ctx) + local location = nil + if ctx.ctype == utils.ctype.blockwise then + location = require("ts_context_commentstring.utils").get_cursor_location() + elseif ctx.cmotion == utils.cmotion.v or ctx.cmotion == utils.cmotion.V then + location = require("ts_context_commentstring.utils").get_visual_start_location() + end + + return require("ts_context_commentstring.internal").calculate_commentstring { + key = ctx.ctype == utils.ctype.linewise and "__default" or "__multiline", + location = location, + } + end, +})) diff --git a/lua/configs/aerial.lua b/lua/configs/aerial.lua new file mode 100644 index 0000000..d4c7310 --- /dev/null +++ b/lua/configs/aerial.lua @@ -0,0 +1,25 @@ +require("aerial").setup(astronvim.user_plugin_opts("plugins.aerial", { + attach_mode = "global", + backends = { "lsp", "treesitter", "markdown", "man" }, + layout = { + min_width = 28, + }, + show_guides = true, + filter_kind = false, + 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, + }, +})) diff --git a/lua/configs/alpha.lua b/lua/configs/alpha.lua new file mode 100644 index 0000000..933dd6b --- /dev/null +++ b/lua/configs/alpha.lua @@ -0,0 +1,36 @@ +require("alpha").setup(astronvim.user_plugin_opts("plugins.alpha", { + layout = { + { type = "padding", val = vim.fn.max { 2, vim.fn.floor(vim.fn.winheight(0) * 0.2) } }, + { + type = "text", + val = astronvim.user_plugin_opts("header", { + " █████ ███████ ████████ ██████ ██████", + "██ ██ ██ ██ ██ ██ ██ ██", + "███████ ███████ ██ ██████ ██ ██", + "██ ██ ██ ██ ██ ██ ██ ██", + "██ ██ ███████ ██ ██ ██ ██████", + " ", + " ███  ██ ██  ██ ██ ███  ███", + " ████  ██ ██  ██ ██ ████  ████", + " ██ ██  ██ ██  ██ ██ ██ ████ ██", + " ██  ██ ██  ██  ██  ██ ██  ██  ██", + " ██   ████   ████   ██ ██      ██", + }, false), + opts = { position = "center", hl = "DashboardHeader" }, + }, + { type = "padding", val = 5 }, + { + type = "group", + val = { + astronvim.alpha_button("LDR f f", " Find File "), + astronvim.alpha_button("LDR f o", " Recents "), + astronvim.alpha_button("LDR f w", " Find Word "), + astronvim.alpha_button("LDR f n", " New File "), + astronvim.alpha_button("LDR f m", " Bookmarks "), + astronvim.alpha_button("LDR S l", " Last Session "), + }, + opts = { spacing = 1 }, + }, + }, + opts = { noautocmd = true }, +})) diff --git a/lua/configs/autopairs.lua b/lua/configs/autopairs.lua new file mode 100644 index 0000000..fb9e086 --- /dev/null +++ b/lua/configs/autopairs.lua @@ -0,0 +1,28 @@ +local npairs = require "nvim-autopairs" +npairs.setup(astronvim.user_plugin_opts("plugins.nvim-autopairs", { + check_ts = true, + ts_config = { java = false }, + fast_wrap = { + map = "", + chars = { "{", "[", "(", '"', "'" }, + pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], "%s+", ""), + offset = 0, + end_key = "$", + keys = "qwertyuiopzxcvbnmasdfghjkl", + check_comma = true, + highlight = "PmenuSel", + highlight_grey = "LineNr", + }, +})) + +if not vim.g.autopairs_enabled then npairs.disable() end + +local rules = astronvim.user_plugin_opts("nvim-autopairs").add_rules +if vim.tbl_contains({ "function", "table" }, type(rules)) then + npairs.add_rules(type(rules) == "function" and rules(npairs) or rules) +end + +local cmp_status_ok, cmp = pcall(require, "cmp") +if cmp_status_ok then + cmp.event:on("confirm_done", require("nvim-autopairs.completion.cmp").on_confirm_done { tex = false }) +end diff --git a/lua/configs/better_escape.lua b/lua/configs/better_escape.lua new file mode 100644 index 0000000..d6afb22 --- /dev/null +++ b/lua/configs/better_escape.lua @@ -0,0 +1 @@ +require("better_escape").setup(astronvim.user_plugin_opts "plugins.better_escape") diff --git a/lua/configs/bufferline.lua b/lua/configs/bufferline.lua new file mode 100644 index 0000000..96626de --- /dev/null +++ b/lua/configs/bufferline.lua @@ -0,0 +1,36 @@ +local close_func = function(bufnum) + local bufdelete_avail, bufdelete = pcall(require, "bufdelete") + if bufdelete_avail then + bufdelete.bufdelete(bufnum, true) + else + vim.cmd.bdelete { args = { bufnum }, bang = true } + end +end +require("bufferline").setup(astronvim.user_plugin_opts("plugins.bufferline", { + options = { + offsets = { + { filetype = "NvimTree", text = "", padding = 1 }, + { filetype = "neo-tree", text = "", padding = 1 }, + { filetype = "Outline", text = "", padding = 1 }, + }, + buffer_close_icon = astronvim.get_icon "BufferClose", + modified_icon = astronvim.get_icon "FileModified", + close_icon = astronvim.get_icon "NeovimClose", + close_command = close_func, + right_mouse_command = close_func, + max_name_length = 14, + max_prefix_length = 13, + tab_size = 20, + separator_style = "thin", + }, +})) +local highlights = require "bufferline.highlights" +vim.api.nvim_create_autocmd("User", { + pattern = "AstroColorScheme", + group = "BufferlineCmds", + desc = "Bufferline apply colors after astronvim colorscheme change", + callback = function() + highlights.reset_icon_hl_cache() + highlights.set_all(require("bufferline.config").update_highlights()) + end, +}) diff --git a/lua/configs/cmp.lua b/lua/configs/cmp.lua new file mode 100644 index 0000000..8255531 --- /dev/null +++ b/lua/configs/cmp.lua @@ -0,0 +1,92 @@ +local cmp = require "cmp" +local snip_status_ok, luasnip = pcall(require, "luasnip") +local lspkind_status_ok, lspkind = pcall(require, "lspkind") +if not snip_status_ok then return end +local setup = cmp.setup +local border_opts = + { border = "single", winhighlight = "Normal:Normal,FloatBorder:FloatBorder,CursorLine:Visual,Search:None" } + +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 + +setup(astronvim.user_plugin_opts("plugins.cmp", { + enabled = function() + if vim.api.nvim_buf_get_option(0, "buftype") == "prompt" then return false end + return vim.g.cmp_enabled + end, + preselect = cmp.PreselectMode.None, + formatting = { + fields = { "kind", "abbr", "menu" }, + format = lspkind_status_ok and lspkind.cmp_format(astronvim.lspkind) or nil, + }, + 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 = { + [""] = cmp.mapping.select_prev_item { behavior = cmp.SelectBehavior.Select }, + [""] = cmp.mapping.select_next_item { behavior = cmp.SelectBehavior.Select }, + [""] = cmp.mapping.select_prev_item { behavior = cmp.SelectBehavior.Insert }, + [""] = cmp.mapping.select_next_item { behavior = cmp.SelectBehavior.Insert }, + [""] = cmp.mapping.select_prev_item { behavior = cmp.SelectBehavior.Insert }, + [""] = cmp.mapping.select_next_item { behavior = cmp.SelectBehavior.Insert }, + [""] = cmp.mapping(cmp.mapping.scroll_docs(-1), { "i", "c" }), + [""] = cmp.mapping(cmp.mapping.scroll_docs(1), { "i", "c" }), + [""] = cmp.mapping(cmp.mapping.complete(), { "i", "c" }), + [""] = cmp.config.disable, + [""] = cmp.mapping { + i = cmp.mapping.abort(), + c = cmp.mapping.close(), + }, + [""] = cmp.mapping.confirm { select = false }, + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item() + elseif luasnip.expandable() then + luasnip.expand() + elseif luasnip.expand_or_jumpable() then + luasnip.expand_or_jump() + elseif has_words_before() then + cmp.complete() + else + fallback() + end + end, { + "i", + "s", + }), + [""] = 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", + }), + }, +})) +for setup_opt, setup_table in pairs(astronvim.user_plugin_opts("cmp.setup", {})) do + for pattern, options in pairs(setup_table) do + setup[setup_opt](pattern, options) + end +end diff --git a/lua/configs/colorizer.lua b/lua/configs/colorizer.lua new file mode 100644 index 0000000..004e89e --- /dev/null +++ b/lua/configs/colorizer.lua @@ -0,0 +1,3 @@ +require("colorizer").setup( + astronvim.user_plugin_opts("plugins.colorizer", { user_default_options = { names = false } }) +) diff --git a/lua/configs/dap.lua b/lua/configs/dap.lua new file mode 100644 index 0000000..def9731 --- /dev/null +++ b/lua/configs/dap.lua @@ -0,0 +1,3 @@ +local dap = require "dap" +dap.adapters = astronvim.user_plugin_opts("dap.adapters", dap.adapters) +dap.configurations = astronvim.user_plugin_opts("dap.configurations", dap.configurations) diff --git a/lua/configs/dapui.lua b/lua/configs/dapui.lua new file mode 100644 index 0000000..144017e --- /dev/null +++ b/lua/configs/dapui.lua @@ -0,0 +1,5 @@ +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(astronvim.user_plugin_opts("plugins.dapui", { floating = { border = "rounded" } })) diff --git a/lua/configs/dressing.lua b/lua/configs/dressing.lua new file mode 100644 index 0000000..837f51b --- /dev/null +++ b/lua/configs/dressing.lua @@ -0,0 +1,10 @@ +require("dressing").setup(astronvim.user_plugin_opts("plugins.dressing", { + input = { + default_prompt = "➤ ", + win_options = { winhighlight = "Normal:Normal,NormalNC:Normal" }, + }, + select = { + backend = { "telescope", "builtin" }, + builtin = { win_options = { winhighlight = "Normal:Normal,NormalNC:Normal" } }, + }, +})) diff --git a/lua/configs/gitsigns.lua b/lua/configs/gitsigns.lua new file mode 100644 index 0000000..92ca456 --- /dev/null +++ b/lua/configs/gitsigns.lua @@ -0,0 +1,10 @@ +require("gitsigns").setup(astronvim.user_plugin_opts("plugins.gitsigns", { + signs = { + add = { text = "▎" }, + change = { text = "▎" }, + delete = { text = "▎" }, + topdelete = { text = "契" }, + changedelete = { text = "▎" }, + untracked = { text = "▎" }, + }, +})) diff --git a/lua/configs/heirline.lua b/lua/configs/heirline.lua new file mode 100644 index 0000000..f5cddb0 --- /dev/null +++ b/lua/configs/heirline.lua @@ -0,0 +1,309 @@ +local heirline = require "heirline" +if not astronvim.status then return end +local C = require "default_theme.colors" + +local function setup_colors() + local Normal = astronvim.get_hlgroup("Normal", { fg = C.fg, bg = C.bg }) + local Comment = astronvim.get_hlgroup("Comment", { fg = C.grey_2, bg = C.bg }) + local Error = astronvim.get_hlgroup("Error", { fg = C.red, bg = C.bg }) + local StatusLine = astronvim.get_hlgroup("StatusLine", { fg = C.fg, bg = C.grey_4 }) + local TabLine = astronvim.get_hlgroup("TabLine", { fg = C.grey, bg = C.none }) + local TabLineSel = astronvim.get_hlgroup("TabLineSel", { fg = C.fg, bg = C.none }) + local WinBar = astronvim.get_hlgroup("WinBar", { fg = C.grey_2, bg = C.bg }) + local WinBarNC = astronvim.get_hlgroup("WinBarNC", { fg = C.grey, bg = C.bg }) + local Conditional = astronvim.get_hlgroup("Conditional", { fg = C.purple_1, bg = C.grey_4 }) + local String = astronvim.get_hlgroup("String", { fg = C.green, bg = C.grey_4 }) + local TypeDef = astronvim.get_hlgroup("TypeDef", { fg = C.yellow, bg = C.grey_4 }) + local GitSignsAdd = astronvim.get_hlgroup("GitSignsAdd", { fg = C.green, bg = C.grey_4 }) + local GitSignsChange = astronvim.get_hlgroup("GitSignsChange", { fg = C.orange_1, bg = C.grey_4 }) + local GitSignsDelete = astronvim.get_hlgroup("GitSignsDelete", { fg = C.red_1, bg = C.grey_4 }) + local DiagnosticError = astronvim.get_hlgroup("DiagnosticError", { fg = C.red_1, bg = C.grey_4 }) + local DiagnosticWarn = astronvim.get_hlgroup("DiagnosticWarn", { fg = C.orange_1, bg = C.grey_4 }) + local DiagnosticInfo = astronvim.get_hlgroup("DiagnosticInfo", { fg = C.white_2, bg = C.grey_4 }) + local DiagnosticHint = astronvim.get_hlgroup("DiagnosticHint", { fg = C.yellow_1, bg = C.grey_4 }) + local HeirlineInactive = astronvim.get_hlgroup("HeirlineInactive", { fg = nil }).fg + or astronvim.status.hl.lualine_mode("inactive", C.grey_7) + local HeirlineNormal = astronvim.get_hlgroup("HeirlineNormal", { fg = nil }).fg + or astronvim.status.hl.lualine_mode("normal", C.blue) + local HeirlineInsert = astronvim.get_hlgroup("HeirlineInsert", { fg = nil }).fg + or astronvim.status.hl.lualine_mode("insert", C.green) + local HeirlineVisual = astronvim.get_hlgroup("HeirlineVisual", { fg = nil }).fg + or astronvim.status.hl.lualine_mode("visual", C.purple) + local HeirlineReplace = astronvim.get_hlgroup("HeirlineReplace", { fg = nil }).fg + or astronvim.status.hl.lualine_mode("replace", C.red_1) + local HeirlineCommand = astronvim.get_hlgroup("HeirlineCommand", { fg = nil }).fg + or astronvim.status.hl.lualine_mode("command", C.yellow_1) + local HeirlineTerminal = astronvim.get_hlgroup("HeirlineTerminal", { fg = nil }).fg + or astronvim.status.hl.lualine_mode("inactive", HeirlineInsert) + + local colors = astronvim.user_plugin_opts("heirline.colors", { + close_fg = Error.fg, + fg = StatusLine.fg, + bg = StatusLine.bg, + section_fg = StatusLine.fg, + section_bg = StatusLine.bg, + git_branch_fg = Conditional.fg, + mode_fg = StatusLine.bg, + treesitter_fg = String.fg, + scrollbar = TypeDef.fg, + git_added = GitSignsAdd.fg, + git_changed = GitSignsChange.fg, + git_removed = GitSignsDelete.fg, + diag_ERROR = DiagnosticError.fg, + diag_WARN = DiagnosticWarn.fg, + diag_INFO = DiagnosticInfo.fg, + diag_HINT = DiagnosticHint.fg, + winbar_fg = WinBar.fg, + winbar_bg = WinBar.bg, + winbarnc_fg = WinBarNC.fg, + winbarnc_bg = WinBarNC.bg, + tabline_bg = StatusLine.bg, + tabline_fg = StatusLine.bg, + buffer_fg = Comment.fg, + buffer_path_fg = WinBarNC.fg, + buffer_close_fg = Comment.fg, + buffer_bg = StatusLine.bg, + buffer_active_fg = Normal.fg, + buffer_active_path_fg = WinBarNC.fg, + buffer_active_close_fg = Error.fg, + buffer_active_bg = Normal.bg, + buffer_visible_fg = Normal.fg, + buffer_visible_path_fg = WinBarNC.fg, + buffer_visible_close_fg = Error.fg, + buffer_visible_bg = Normal.bg, + buffer_overflow_fg = Comment.fg, + buffer_overflow_bg = StatusLine.bg, + buffer_picker_fg = Error.fg, + tab_close_fg = Error.fg, + tab_close_bg = StatusLine.bg, + tab_fg = TabLine.fg, + tab_bg = TabLine.bg, + tab_active_fg = TabLineSel.fg, + tab_active_bg = TabLineSel.bg, + inactive = HeirlineInactive, + normal = HeirlineNormal, + insert = HeirlineInsert, + visual = HeirlineVisual, + replace = HeirlineReplace, + command = HeirlineCommand, + terminal = HeirlineTerminal, + }) + + for _, section in ipairs { + "git_branch", + "file_info", + "git_diff", + "diagnostics", + "lsp", + "macro_recording", + "mode", + "cmd_info", + "treesitter", + "nav", + } do + if not colors[section .. "_bg"] then colors[section .. "_bg"] = colors["section_bg"] end + if not colors[section .. "_fg"] then colors[section .. "_fg"] = colors["section_fg"] end + end + return colors +end + +--- a submodule of heirline specific functions and aliases +astronvim.status.heirline = {} + +--- A helper function to get the type a tab or buffer is +-- @param self the self table from a heirline component function +-- @param prefix the prefix of the type, either "tab" or "buffer" (Default: "buffer") +-- @return the string of prefix with the type (i.e. "_active" or "_visible") +function astronvim.status.heirline.tab_type(self, prefix) + local tab_type = "" + if self.is_active then + tab_type = "_active" + elseif self.is_visible then + tab_type = "_visible" + end + return (prefix or "buffer") .. tab_type +end + +--- Make a list of buffers, rendering each buffer with the provided component +---@param component table +---@return table +astronvim.status.heirline.make_buflist = function(component) + local overflow_hl = astronvim.status.hl.get_attributes("buffer_overflow", true) + return require("heirline.utils").make_buflist( + astronvim.status.utils.surround( + "tab", + function(self) + return { + main = astronvim.status.heirline.tab_type(self) .. "_bg", + left = "tabline_bg", + right = "tabline_bg", + } + end, + { -- bufferlist + init = function(self) self.tab_type = astronvim.status.heirline.tab_type(self) end, + on_click = { -- add clickable component to each buffer + callback = function(_, minwid) vim.api.nvim_win_set_buf(0, minwid) end, + minwid = function(self) return self.bufnr end, + name = "heirline_tabline_buffer_callback", + }, + { -- add buffer picker functionality to each buffer + condition = function(self) return self._show_picker end, + update = false, + init = function(self) + local bufname = astronvim.status.provider.filename { fallback = "empty_file" }(self) + local label = bufname:sub(1, 1) + local i = 2 + while label ~= " " and self._picker_labels[label] do + if i > #bufname then break end + label = bufname:sub(i, i) + i = i + 1 + end + self._picker_labels[label] = self.bufnr + self.label = label + end, + provider = function(self) + return astronvim.status.provider.str { str = self.label, padding = { left = 1, right = 1 } } + end, + hl = astronvim.status.hl.get_attributes "buffer_picker", + }, + component, -- create buffer component + }, + false -- disable surrounding + ), + { provider = astronvim.get_icon "ArrowLeft" .. " ", hl = overflow_hl }, + { provider = astronvim.get_icon "ArrowRight" .. " ", hl = overflow_hl }, + function() return vim.t.bufs end, -- use astronvim bufs variable + false -- disable internal caching + ) +end + +--- Alias to require("heirline.utils").make_tablist +astronvim.status.heirline.make_tablist = require("heirline.utils").make_tablist + +--- Run the buffer picker and execute the callback function on the selected buffer +-- @param callback function with a single parameter of the buffer number +function astronvim.status.heirline.buffer_picker(callback) + local tabline = require("heirline").tabline + local buflist = tabline and tabline._buflist[1] + if buflist then + local prev_showtabline = vim.opt.showtabline + buflist._picker_labels = {} + buflist._show_picker = true + vim.opt.showtabline = 2 + vim.cmd.redrawtabline() + local char = vim.fn.getcharstr() + local bufnr = buflist._picker_labels[char] + if bufnr then callback(bufnr) end + buflist._show_picker = false + vim.opt.showtabline = prev_showtabline + vim.cmd.redrawtabline() + end +end + +heirline.load_colors(setup_colors()) +local heirline_opts = astronvim.user_plugin_opts("plugins.heirline", { + { -- statusline + hl = { fg = "fg", bg = "bg" }, + astronvim.status.component.mode(), + astronvim.status.component.git_branch(), + -- TODO: REMOVE THIS WITH v3 + astronvim.status.component.file_info( + (astronvim.is_available "bufferline.nvim" or vim.g.heirline_bufferline) + and { filetype = {}, filename = false, file_modified = false } + or nil + ), + -- astronvim.status.component.file_info { filetype = {}, filename = false, file_modified = false }, + astronvim.status.component.git_diff(), + astronvim.status.component.diagnostics(), + astronvim.status.component.fill(), + astronvim.status.component.cmd_info(), + astronvim.status.component.fill(), + astronvim.status.component.lsp(), + astronvim.status.component.treesitter(), + astronvim.status.component.nav(), + astronvim.status.component.mode { surround = { separator = "right" } }, + }, + { -- winbar + static = { + disabled = { + buftype = { "terminal", "prompt", "nofile", "help", "quickfix" }, + filetype = { "NvimTree", "neo%-tree", "dashboard", "Outline", "aerial" }, + }, + }, + init = function(self) self.bufnr = vim.api.nvim_get_current_buf() end, + fallthrough = false, + { + condition = function(self) + return vim.opt.diff:get() or astronvim.status.condition.buffer_matches(self.disabled or {}) + end, + init = function() vim.opt_local.winbar = nil end, + }, + astronvim.status.component.file_info { + condition = function() return not astronvim.status.condition.is_active() end, + unique_path = {}, + file_icon = { hl = astronvim.status.hl.file_icon "winbar" }, + file_modified = false, + file_read_only = false, + hl = astronvim.status.hl.get_attributes("winbarnc", true), + surround = false, + update = "BufEnter", + }, + astronvim.status.component.breadcrumbs { hl = astronvim.status.hl.get_attributes("winbar", true) }, + }, + vim.g.heirline_bufferline -- TODO v3: remove this option and make bufferline default + and { -- bufferline + { -- file tree padding + condition = function(self) + self.winid = vim.api.nvim_tabpage_list_wins(0)[1] + return astronvim.status.condition.buffer_matches( + { filetype = { "neo%-tree", "NvimTree" } }, + vim.api.nvim_win_get_buf(self.winid) + ) + end, + provider = function(self) return string.rep(" ", vim.api.nvim_win_get_width(self.winid)) end, + hl = { bg = "tabline_bg" }, + }, + astronvim.status.heirline.make_buflist(astronvim.status.component.tabline_file_info()), -- component for each buffer tab + astronvim.status.component.fill { hl = { bg = "tabline_bg" } }, -- fill the rest of the tabline with background color + { -- tab list + condition = function() return #vim.api.nvim_list_tabpages() >= 2 end, -- only show tabs if there are more than one + astronvim.status.heirline.make_tablist { -- component for each tab + provider = astronvim.status.provider.tabnr(), + hl = function(self) + return astronvim.status.hl.get_attributes(astronvim.status.heirline.tab_type(self, "tab"), true) + end, + }, + { -- close button for current tab + provider = astronvim.status.provider.close_button { kind = "TabClose", padding = { left = 1, right = 1 } }, + hl = astronvim.status.hl.get_attributes("tab_close", true), + on_click = { callback = astronvim.close_tab, name = "heirline_tabline_close_tab_callback" }, + }, + }, + } + or nil, +}) +heirline.setup(heirline_opts[1], heirline_opts[2], heirline_opts[3]) + +local augroup = vim.api.nvim_create_augroup("Heirline", { clear = true }) +vim.api.nvim_create_autocmd("User", { + pattern = "AstroColorScheme", + group = augroup, + desc = "Refresh heirline colors", + callback = function() require("heirline.utils").on_colorscheme(setup_colors()) end, +}) +vim.api.nvim_create_autocmd("User", { + pattern = "HeirlineInitWinbar", + group = augroup, + desc = "Disable winbar for some filetypes", + callback = function() + if + vim.opt.diff:get() + or astronvim.status.condition.buffer_matches(require("heirline").winbar.disabled or { + buftype = { "terminal", "prompt", "nofile", "help", "quickfix" }, + filetype = { "NvimTree", "neo%-tree", "dashboard", "Outline", "aerial" }, + }) -- TODO v3: remove the default fallback here + then + vim.opt_local.winbar = nil + end + end, +}) diff --git a/lua/configs/indent-line.lua b/lua/configs/indent-line.lua new file mode 100644 index 0000000..0adb603 --- /dev/null +++ b/lua/configs/indent-line.lua @@ -0,0 +1,45 @@ +require("indent_blankline").setup(astronvim.user_plugin_opts("plugins.indent_blankline", { + buftype_exclude = { + "nofile", + "terminal", + }, + filetype_exclude = { + "help", + "startify", + "aerial", + "alpha", + "dashboard", + "packer", + "neogitstatus", + "NvimTree", + "neo-tree", + "Trouble", + }, + context_patterns = { + "class", + "return", + "function", + "method", + "^if", + "^while", + "jsx_element", + "^for", + "^object", + "^table", + "block", + "arguments", + "if_statement", + "else_clause", + "jsx_element", + "jsx_self_closing_element", + "try_statement", + "catch_clause", + "import_statement", + "operation_type", + }, + show_trailing_blankline_indent = false, + use_treesitter = true, + char = "▏", + context_char = "▏", + show_current_context = true, +})) diff --git a/lua/configs/indent-o-matic.lua b/lua/configs/indent-o-matic.lua new file mode 100644 index 0000000..490ca08 --- /dev/null +++ b/lua/configs/indent-o-matic.lua @@ -0,0 +1,3 @@ +local indent_o_matic = require "indent-o-matic" +indent_o_matic.setup(astronvim.user_plugin_opts "plugins.indent-o-matic") +indent_o_matic.detect() diff --git a/lua/configs/lspconfig.lua b/lua/configs/lspconfig.lua new file mode 100644 index 0000000..96bf7ab --- /dev/null +++ b/lua/configs/lspconfig.lua @@ -0,0 +1,13 @@ +if vim.g.lsp_handlers_enabled then + vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded" }) + vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = "rounded" }) +end +local setup_servers = function() + vim.tbl_map(astronvim.lsp.setup, astronvim.user_plugin_opts "lsp.servers") + vim.cmd "silent! do FileType" +end +if astronvim.is_available "mason-lspconfig.nvim" then + vim.api.nvim_create_autocmd("User", { pattern = "AstroLspSetup", once = true, callback = setup_servers }) +else + setup_servers() +end diff --git a/lua/configs/lspkind.lua b/lua/configs/lspkind.lua new file mode 100644 index 0000000..6f13763 --- /dev/null +++ b/lua/configs/lspkind.lua @@ -0,0 +1,23 @@ +astronvim.lspkind = astronvim.user_plugin_opts("plugins.lspkind", { + mode = "symbol", + symbol_map = { + NONE = "", + Array = "", + Boolean = "⊨", + Class = "", + Constructor = "", + Key = "", + Namespace = "", + Null = "NULL", + Number = "#", + Object = "⦿", + Package = "", + Property = "", + Reference = "", + Snippet = "", + String = "𝓐", + TypeParameter = "", + Unit = "", + }, +}) +require("lspkind").init(astronvim.lspkind) diff --git a/lua/configs/luasnip.lua b/lua/configs/luasnip.lua new file mode 100644 index 0000000..5ee7d14 --- /dev/null +++ b/lua/configs/luasnip.lua @@ -0,0 +1,17 @@ +local user_settings = astronvim.user_plugin_opts "luasnip" +local luasnip = require "luasnip" +if user_settings.config then luasnip.config.setup(user_settings.config) end +for _, load_type in ipairs { "vscode", "snipmate", "lua" } do + local loader = require("luasnip.loaders.from_" .. load_type) + loader.lazy_load() + -- TODO: DEPRECATE _snippet_paths option in next major version release + local paths = user_settings[load_type .. "_snippet_paths"] + if paths then loader.lazy_load { paths = paths } end + local loader_settings = user_settings[load_type] + if loader_settings then loader.lazy_load(loader_settings) end +end +if type(user_settings.filetype_extend) == "table" then + for filetype, snippets in pairs(user_settings.filetype_extend) do + luasnip.filetype_extend(filetype, snippets) + end +end diff --git a/lua/configs/mason-lspconfig.lua b/lua/configs/mason-lspconfig.lua new file mode 100644 index 0000000..8fb1efd --- /dev/null +++ b/lua/configs/mason-lspconfig.lua @@ -0,0 +1,6 @@ +local mason_lspconfig = require "mason-lspconfig" +mason_lspconfig.setup(astronvim.user_plugin_opts "plugins.mason-lspconfig") +mason_lspconfig.setup_handlers( + astronvim.user_plugin_opts("mason-lspconfig.setup_handlers", { function(server) astronvim.lsp.setup(server) end }) +) +astronvim.event "LspSetup" diff --git a/lua/configs/mason-null-ls.lua b/lua/configs/mason-null-ls.lua new file mode 100644 index 0000000..fe398de --- /dev/null +++ b/lua/configs/mason-null-ls.lua @@ -0,0 +1,3 @@ +local mason_null_ls = require "mason-null-ls" +mason_null_ls.setup(astronvim.user_plugin_opts("plugins.mason-null-ls", { automatic_setup = true })) +mason_null_ls.setup_handlers(astronvim.user_plugin_opts("mason-null-ls.setup_handlers", {})) diff --git a/lua/configs/mason-nvim-dap.lua b/lua/configs/mason-nvim-dap.lua new file mode 100644 index 0000000..c7c60a8 --- /dev/null +++ b/lua/configs/mason-nvim-dap.lua @@ -0,0 +1,3 @@ +local mason_nvim_dap = require "mason-nvim-dap" +mason_nvim_dap.setup(astronvim.user_plugin_opts("plugins.mason-nvim-dap", { automatic_setup = true })) +mason_nvim_dap.setup_handlers(astronvim.user_plugin_opts("mason-nvim-dap.setup_handlers", {})) diff --git a/lua/configs/mason.lua b/lua/configs/mason.lua new file mode 100644 index 0000000..f5b3fca --- /dev/null +++ b/lua/configs/mason.lua @@ -0,0 +1,13 @@ +require("mason").setup(astronvim.user_plugin_opts("plugins.mason", { + ui = { + icons = { + package_installed = "✓", + package_uninstalled = "✗", + package_pending = "⟳", + }, + }, +})) + +local cmd = vim.api.nvim_create_user_command +cmd("MasonUpdateAll", function() astronvim.mason.update_all() end, { desc = "Update Mason Packages" }) +cmd("MasonUpdate", function(opts) astronvim.mason.update(opts.args) end, { nargs = 1, desc = "Update Mason Package" }) diff --git a/lua/configs/neo-tree.lua b/lua/configs/neo-tree.lua new file mode 100644 index 0000000..e35655e --- /dev/null +++ b/lua/configs/neo-tree.lua @@ -0,0 +1,67 @@ +require("neo-tree").setup(astronvim.user_plugin_opts("plugins.neo-tree", { + close_if_last_window = true, + enable_diagnostics = false, + source_selector = { + winbar = true, + content_layout = "center", + tab_labels = { + filesystem = astronvim.get_icon "FolderClosed" .. " File", + buffers = astronvim.get_icon "DefaultFile" .. " Bufs", + git_status = astronvim.get_icon "Git" .. " Git", + diagnostics = astronvim.get_icon "Diagnostic" .. " Diagnostic", + }, + }, + default_component_configs = { + indent = { padding = 0 }, + icon = { + folder_closed = astronvim.get_icon "FolderClosed", + folder_open = astronvim.get_icon "FolderOpen", + folder_empty = astronvim.get_icon "FolderEmpty", + default = astronvim.get_icon "DefaultFile", + }, + git_status = { + symbols = { + added = astronvim.get_icon "GitAdd", + deleted = astronvim.get_icon "GitDelete", + modified = astronvim.get_icon "GitChange", + renamed = astronvim.get_icon "GitRenamed", + untracked = astronvim.get_icon "GitUntracked", + ignored = astronvim.get_icon "GitIgnored", + unstaged = astronvim.get_icon "GitUnstaged", + staged = astronvim.get_icon "GitStaged", + conflict = astronvim.get_icon "GitConflict", + }, + }, + }, + window = { + width = 30, + mappings = { + [""] = false, -- disable space until we figure out which-key disabling + o = "open", + H = "prev_source", + L = "next_source", + }, + }, + filesystem = { + filtered_items = { + visible = true, + hide_dotfiles = false, + hide_gitignored = false, + }, + follow_current_file = true, + hijack_netrw_behavior = "open_current", + use_libuv_file_watcher = true, + window = { + mappings = { + O = "system_open", + h = "toggle_hidden", + }, + }, + commands = { + system_open = function(state) astronvim.system_open(state.tree:get_node():get_id()) end, + }, + }, + event_handlers = { + { event = "neo_tree_buffer_enter", handler = function(_) vim.opt_local.signcolumn = "auto" end }, + }, +})) diff --git a/lua/configs/notify.lua b/lua/configs/notify.lua new file mode 100644 index 0000000..a4388fb --- /dev/null +++ b/lua/configs/notify.lua @@ -0,0 +1,3 @@ +local notify = require "notify" +notify.setup(astronvim.user_plugin_opts("plugins.notify", { stages = "fade" })) +vim.notify = notify diff --git a/lua/configs/null-ls.lua b/lua/configs/null-ls.lua new file mode 100644 index 0000000..e1eca3b --- /dev/null +++ b/lua/configs/null-ls.lua @@ -0,0 +1 @@ +require("null-ls").setup(astronvim.user_plugin_opts("plugins.null-ls", { on_attach = astronvim.lsp.on_attach })) diff --git a/lua/configs/nvim-web-devicons.lua b/lua/configs/nvim-web-devicons.lua new file mode 100644 index 0000000..54f4615 --- /dev/null +++ b/lua/configs/nvim-web-devicons.lua @@ -0,0 +1,15 @@ +require("nvim-web-devicons").set_default_icon(astronvim.get_icon "DefaultFile", "#6d8086", "66") +require("nvim-web-devicons").set_icon(astronvim.user_plugin_opts("plugins.nvim-web-devicons", { + 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" }, +})) diff --git a/lua/configs/server-settings/jsonls.lua b/lua/configs/server-settings/jsonls.lua new file mode 100644 index 0000000..98da93b --- /dev/null +++ b/lua/configs/server-settings/jsonls.lua @@ -0,0 +1,8 @@ +return { + settings = { + json = { + schemas = require("schemastore").json.schemas(), + validate = { enable = true }, + }, + }, +} diff --git a/lua/configs/server-settings/sumneko_lua.lua b/lua/configs/server-settings/sumneko_lua.lua new file mode 100644 index 0000000..378f7c3 --- /dev/null +++ b/lua/configs/server-settings/sumneko_lua.lua @@ -0,0 +1,16 @@ +return { + settings = { + Lua = { + telemetry = { enable = false }, + runtime = { version = "LuaJIT" }, + diagnostics = { globals = { "vim", "astronvim", "astronvim_installation", "packer_plugins", "bit" } }, + workspace = { + library = { + vim.fn.expand "$VIMRUNTIME/lua", + astronvim.install.home .. "/lua", + astronvim.install.config .. "/lua", + }, + }, + }, + }, +} diff --git a/lua/configs/session_manager.lua b/lua/configs/session_manager.lua new file mode 100644 index 0000000..409a1dd --- /dev/null +++ b/lua/configs/session_manager.lua @@ -0,0 +1 @@ +require("session_manager").setup(astronvim.user_plugin_opts "plugins.session_manager") diff --git a/lua/configs/smart-splits.lua b/lua/configs/smart-splits.lua new file mode 100644 index 0000000..f43f7ac --- /dev/null +++ b/lua/configs/smart-splits.lua @@ -0,0 +1,9 @@ +require("smart-splits").setup(astronvim.user_plugin_opts("plugins.smart-splits", { + ignored_filetypes = { + "nofile", + "quickfix", + "qf", + "prompt", + }, + ignored_buftypes = { "nofile" }, +})) diff --git a/lua/configs/telescope.lua b/lua/configs/telescope.lua new file mode 100644 index 0000000..cc659ba --- /dev/null +++ b/lua/configs/telescope.lua @@ -0,0 +1,39 @@ +local telescope = require "telescope" +local actions = require "telescope.actions" + +telescope.setup(astronvim.user_plugin_opts("plugins.telescope", { + defaults = { + file_ignore_patterns = { "node_modules" }, + + prompt_prefix = string.format("%s ", astronvim.get_icon "Search"), + selection_caret = string.format("%s ", astronvim.get_icon "Selected"), + path_display = { "truncate" }, + sorting_strategy = "ascending", + layout_config = { + horizontal = { + prompt_position = "top", + preview_width = 0.55, + results_width = 0.8, + }, + vertical = { + mirror = false, + }, + width = 0.87, + height = 0.80, + preview_cutoff = 120, + }, + + mappings = { + i = { + [""] = actions.cycle_history_next, + [""] = actions.cycle_history_prev, + [""] = actions.move_selection_next, + [""] = actions.move_selection_previous, + }, + n = { ["q"] = actions.close }, + }, + }, +})) + +astronvim.conditional_func(telescope.load_extension, pcall(require, "notify"), "notify") +astronvim.conditional_func(telescope.load_extension, pcall(require, "aerial"), "aerial") diff --git a/lua/configs/toggleterm.lua b/lua/configs/toggleterm.lua new file mode 100644 index 0000000..8fb1444 --- /dev/null +++ b/lua/configs/toggleterm.lua @@ -0,0 +1,13 @@ +require("toggleterm").setup(astronvim.user_plugin_opts("plugins.toggleterm", { + size = 10, + open_mapping = [[]], + shading_factor = 2, + direction = "float", + float_opts = { + border = "curved", + highlights = { + border = "Normal", + background = "Normal", + }, + }, +})) diff --git a/lua/configs/treesitter.lua b/lua/configs/treesitter.lua new file mode 100644 index 0000000..bf024f9 --- /dev/null +++ b/lua/configs/treesitter.lua @@ -0,0 +1,19 @@ +require("nvim-treesitter.configs").setup(astronvim.user_plugin_opts("plugins.treesitter", { + highlight = { + enable = true, + additional_vim_regex_highlighting = false, + }, + context_commentstring = { + enable = true, + enable_autocmd = false, + }, + rainbow = { + enable = true, + disable = { "html" }, + extended_mode = false, + max_file_lines = nil, + }, + autotag = { enable = true }, + incremental_selection = { enable = true }, + indent = { enable = false }, +})) diff --git a/lua/configs/which-key-register.lua b/lua/configs/which-key-register.lua new file mode 100644 index 0000000..e5d38b7 --- /dev/null +++ b/lua/configs/which-key-register.lua @@ -0,0 +1,55 @@ +local is_available = astronvim.is_available +local user_plugin_opts = astronvim.user_plugin_opts +local mappings = { + n = { + [""] = { + f = { name = "File" }, + p = { name = "Packages" }, + l = { name = "LSP" }, + u = { name = "UI" }, + }, + }, +} + +local extra_sections = { + b = "Buffers", + D = "Debugger", + g = "Git", + s = "Search", + S = "Session", + t = "Terminal", +} + +local function init_table(mode, prefix, idx) + if not mappings[mode][prefix][idx] then mappings[mode][prefix][idx] = { name = extra_sections[idx] } end +end + +-- TODO v3: remove vim.g.heirline_bufferline check +if is_available "heirline.nvim" and vim.g.heirline_bufferline then init_table("n", "", "b") end + +if is_available "neovim-session-manager" then init_table("n", "", "S") end + +if is_available "gitsigns.nvim" then init_table("n", "", "g") end + +if is_available "toggleterm.nvim" then + init_table("n", "", "g") + init_table("n", "", "t") +end + +if is_available "telescope.nvim" then + init_table("n", "", "s") + init_table("n", "", "g") +end + +if is_available "nvim-dap" then init_table("n", "", "D") end + +if is_available "Comment.nvim" then + for _, mode in ipairs { "n", "v" } do + if not mappings[mode] then mappings[mode] = {} end + if not mappings[mode].g then mappings[mode].g = {} end + mappings[mode].g.c = "Comment toggle linewise" + mappings[mode].g.b = "Comment toggle blockwise" + end +end + +astronvim.which_key_register(user_plugin_opts("which-key.register", mappings)) diff --git a/lua/configs/which-key.lua b/lua/configs/which-key.lua new file mode 100644 index 0000000..b2061c0 --- /dev/null +++ b/lua/configs/which-key.lua @@ -0,0 +1,11 @@ +require("which-key").setup(astronvim.user_plugin_opts("plugins.which-key", { + plugins = { + spelling = { enabled = true }, + presets = { operators = false }, + }, + window = { + border = "rounded", + padding = { 2, 2, 2, 2 }, + }, + disable = { filetypes = { "TelescopePrompt" } }, +})) diff --git a/lua/configs/window-picker.lua b/lua/configs/window-picker.lua new file mode 100644 index 0000000..b8df293 --- /dev/null +++ b/lua/configs/window-picker.lua @@ -0,0 +1,4 @@ +local colors = require "default_theme.colors" +require("window-picker").setup( + astronvim.user_plugin_opts("plugins.window-picker", { use_winbar = "smart", other_win_hl_color = colors.grey_4 }) +) diff --git a/lua/core/autocmds.lua b/lua/core/autocmds.lua new file mode 100644 index 0000000..1e4ba05 --- /dev/null +++ b/lua/core/autocmds.lua @@ -0,0 +1,213 @@ +local is_available = astronvim.is_available +local user_plugin_opts = astronvim.user_plugin_opts +local namespace = vim.api.nvim_create_namespace +local cmd = vim.api.nvim_create_autocmd +local augroup = vim.api.nvim_create_augroup +local create_command = vim.api.nvim_create_user_command + +vim.on_key(function(char) + if vim.fn.mode() == "n" then + local new_hlsearch = vim.tbl_contains({ "", "n", "N", "*", "#", "?", "/" }, vim.fn.keytrans(char)) + if vim.opt.hlsearch:get() ~= new_hlsearch then vim.opt.hlsearch = new_hlsearch end + end +end, namespace "auto_hlsearch") + +if vim.g.heirline_bufferline then + local bufferline_group = augroup("bufferline", { clear = true }) + cmd({ "BufAdd", "BufEnter" }, { + desc = "Update buffers when adding new buffers", + group = bufferline_group, + callback = function(args) + if not vim.t.bufs then vim.t.bufs = {} end + local bufs = vim.t.bufs + if not vim.tbl_contains(bufs, args.buf) then + table.insert(bufs, args.buf) + vim.t.bufs = bufs + end + vim.t.bufs = vim.tbl_filter(astronvim.is_valid_buffer, vim.t.bufs) + end, + }) + cmd("BufDelete", { + desc = "Update buffers when deleting buffers", + group = bufferline_group, + callback = function(args) + for _, tab in ipairs(vim.api.nvim_list_tabpages()) do + local bufs = vim.t[tab].bufs + if bufs then + for i, bufnr in ipairs(bufs) do + if bufnr == args.buf then + table.remove(bufs, i) + vim.t[tab].bufs = bufs + break + end + end + end + end + vim.t.bufs = vim.tbl_filter(astronvim.is_valid_buffer, vim.t.bufs) + vim.cmd.redrawtabline() + end, + }) +end + +cmd({ "VimEnter", "FileType", "BufEnter", "WinEnter" }, { + desc = "URL Highlighting", + group = augroup("highlighturl", { clear = true }), + pattern = "*", + callback = function() astronvim.set_url_match() end, +}) + +cmd("TextYankPost", { + desc = "Highlight yanked text", + group = augroup("highlightyank", { clear = true }), + pattern = "*", + callback = function() vim.highlight.on_yank() end, +}) + +cmd("FileType", { + desc = "Unlist quickfist buffers", + group = augroup("unlist_quickfist", { clear = true }), + pattern = "qf", + callback = function() vim.opt_local.buflisted = false end, +}) + +cmd("BufEnter", { + desc = "Quit AstroNvim if more than one window is open and only sidebar windows are list", + group = augroup("auto_quit", { clear = true }), + callback = function() + local wins = vim.api.nvim_tabpage_list_wins(0) + -- Both neo-tree and aerial will auto-quit if there is only a single window left + if #wins <= 1 then return end + local sidebar_fts = { aerial = true, ["neo-tree"] = true } + for _, winid in ipairs(wins) do + if vim.api.nvim_win_is_valid(winid) then + local bufnr = vim.api.nvim_win_get_buf(winid) + local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype") + -- If any visible windows are not sidebars, early return + if not sidebar_fts[filetype] then + return + -- If the visible window is a sidebar + else + -- only count filetypes once, so remove a found sidebar from the detection + sidebar_fts[filetype] = nil + end + end + end + if #vim.api.nvim_list_tabpages() > 1 then + vim.cmd.tabclose() + else + vim.cmd.qall() + end + end, +}) + +if is_available "alpha-nvim" then + local group_name = augroup("alpha_settings", { clear = true }) + cmd("User", { + desc = "Disable status and tablines for alpha", + group = group_name, + pattern = "AlphaReady", + callback = function() + local prev_showtabline = vim.opt.showtabline + local prev_status = vim.opt.laststatus + vim.opt.laststatus = 0 + vim.opt.showtabline = 0 + vim.opt_local.winbar = nil + cmd("BufUnload", { + pattern = "", + callback = function() + vim.opt.laststatus = prev_status + vim.opt.showtabline = prev_showtabline + end, + }) + end, + }) + cmd("VimEnter", { + desc = "Start Alpha when vim is opened with no arguments", + group = group_name, + callback = function() + local should_skip = false + if vim.fn.argc() > 0 or vim.fn.line2byte "$" ~= -1 or not vim.o.modifiable then + should_skip = true + else + for _, arg in pairs(vim.v.argv) do + if arg == "-b" or arg == "-c" or vim.startswith(arg, "+") or arg == "-S" then + should_skip = true + break + end + end + end + if not should_skip then + if is_available "bufferline.nvim" then pcall(require, "bufferline") end -- TODO v3: remove this line + require("alpha").start(true) + end + end, + }) +end + +if is_available "neo-tree.nvim" then + cmd("BufEnter", { + desc = "Open Neo-Tree on startup with directory", + group = augroup("neotree_start", { clear = true }), + callback = function() + local stats = vim.loop.fs_stat(vim.api.nvim_buf_get_name(0)) + if stats and stats.type == "directory" then require("neo-tree.setup.netrw").hijack() end + end, + }) +end + +if is_available "nvim-dap-ui" then + vim.api.nvim_create_autocmd("FileType", { + desc = "Make q close dap floating windows", + group = vim.api.nvim_create_augroup("dapui", { clear = true }), + pattern = "dap-float", + callback = function() vim.keymap.set("n", "q", "close!") end, + }) +end + +cmd({ "VimEnter", "ColorScheme" }, { + desc = "Load custom highlights from user configuration", + group = augroup("astronvim_highlights", { clear = true }), + callback = function() + if vim.g.colors_name then + for _, module in ipairs { "init", vim.g.colors_name } do + for group, spec in pairs(user_plugin_opts("highlights." .. module)) do + vim.api.nvim_set_hl(0, group, spec) + end + end + end + astronvim.event "ColorScheme" + end, +}) + +vim.api.nvim_create_autocmd("BufRead", { + group = vim.api.nvim_create_augroup("git_plugin_lazy_load", { clear = true }), + callback = function() + vim.fn.system("git -C " .. vim.fn.expand "%:p:h" .. " rev-parse") + if vim.v.shell_error == 0 then + vim.api.nvim_del_augroup_by_name "git_plugin_lazy_load" + local packer = require "packer" + vim.tbl_map(function(plugin) packer.loader(plugin) end, astronvim.git_plugins) + end + end, +}) +vim.api.nvim_create_autocmd({ "BufRead", "BufWinEnter", "BufNewFile" }, { + group = vim.api.nvim_create_augroup("file_plugin_lazy_load", { clear = true }), + callback = function(args) + if not (vim.fn.expand "%" == "" or vim.api.nvim_buf_get_option(args.buf, "buftype") == "nofile") then + vim.api.nvim_del_augroup_by_name "file_plugin_lazy_load" + local packer = require "packer" + vim.tbl_map(function(plugin) packer.loader(plugin) end, astronvim.file_plugins) + end + end, +}) + +create_command( + "AstroUpdatePackages", + function() astronvim.updater.update_packages() end, + { desc = "Update Packer and Mason" } +) +create_command("AstroUpdate", function() astronvim.updater.update() end, { desc = "Update AstroNvim" }) +create_command("AstroReload", function() astronvim.updater.reload() end, { desc = "Reload AstroNvim" }) +create_command("AstroVersion", function() astronvim.updater.version() end, { desc = "Check AstroNvim Version" }) +create_command("AstroChangelog", function() astronvim.updater.changelog() end, { desc = "Check AstroNvim Changelog" }) +create_command("ToggleHighlightURL", function() astronvim.ui.toggle_url_match() end, { desc = "Toggle URL Highlights" }) diff --git a/lua/core/bootstrap.lua b/lua/core/bootstrap.lua new file mode 100644 index 0000000..48839f8 --- /dev/null +++ b/lua/core/bootstrap.lua @@ -0,0 +1,4 @@ +astronvim.initialize_packer() + +local colorscheme = astronvim.user_plugin_opts("colorscheme", nil, false) +vim.cmd.colorscheme(vim.tbl_contains(vim.fn.getcompletion("", "color"), colorscheme) and colorscheme or "default_theme") diff --git a/lua/core/diagnostics.lua b/lua/core/diagnostics.lua new file mode 100644 index 0000000..c214098 --- /dev/null +++ b/lua/core/diagnostics.lua @@ -0,0 +1,43 @@ +local signs = { + { name = "DiagnosticSignError", text = astronvim.get_icon "DiagnosticError" }, + { name = "DiagnosticSignWarn", text = astronvim.get_icon "DiagnosticWarn" }, + { name = "DiagnosticSignHint", text = astronvim.get_icon "DiagnosticHint" }, + { name = "DiagnosticSignInfo", text = astronvim.get_icon "DiagnosticInfo" }, + { name = "DiagnosticSignError", text = astronvim.get_icon "DiagnosticError" }, + { name = "DapStopped", text = astronvim.get_icon "DapStopped", texthl = "DiagnosticWarn" }, + { name = "DapBreakpoint", text = astronvim.get_icon "DapBreakpoint", texthl = "DiagnosticInfo" }, + { name = "DapBreakpointRejected", text = astronvim.get_icon "DapBreakpointRejected", texthl = "DiagnosticError" }, + { name = "DapBreakpointCondition", text = astronvim.get_icon "DapBreakpointCondition", texthl = "DiagnosticInfo" }, + { name = "DapLogPoint", text = astronvim.get_icon "DapLogPoint", texthl = "DiagnosticInfo" }, +} + +for _, sign in ipairs(signs) do + if not sign.texthl then sign.texthl = sign.name end + vim.fn.sign_define(sign.name, sign) +end + +astronvim.lsp.diagnostics = { + off = { + underline = false, + virtual_text = false, + signs = false, + update_in_insert = false, + }, + on = astronvim.user_plugin_opts("diagnostics", { + virtual_text = true, + signs = { active = signs }, + update_in_insert = true, + underline = true, + severity_sort = true, + float = { + focused = false, + style = "minimal", + border = "rounded", + source = "always", + header = "", + prefix = "", + }, + }), +} + +vim.diagnostic.config(astronvim.lsp.diagnostics[vim.g.diagnostics_enabled and "on" or "off"]) diff --git a/lua/core/icons/nerd_font.lua b/lua/core/icons/nerd_font.lua new file mode 100644 index 0000000..b083a06 --- /dev/null +++ b/lua/core/icons/nerd_font.lua @@ -0,0 +1,46 @@ +return { + ActiveLSP = "", + ActiveTS = "綠", + ArrowLeft = "", + ArrowRight = "", + BufferClose = "", + DapBreakpoint = "", + DapBreakpointCondition = "", + DapBreakpointRejected = "", + DapLogPoint = ".>", + DapStopped = "", + DefaultFile = "", + Diagnostic = "裂", + DiagnosticError = "", + DiagnosticHint = "", + DiagnosticInfo = "", + DiagnosticWarn = "", + Ellipsis = "…", + FileModified = "", + FileReadOnly = "", + FolderClosed = "", + FolderEmpty = "", + FolderOpen = "", + Git = "", + GitAdd = "", + GitBranch = "", + GitChange = "", + GitConflict = "", + GitDelete = "", + GitIgnored = "◌", + GitRenamed = "➜", + GitStaged = "✓", + GitUnstaged = "✗", + GitUntracked = "★", + LSPLoaded = "", + LSPLoading1 = "", + LSPLoading2 = "", + LSPLoading3 = "", + MacroRecording = "", + NeovimClose = "", -- TODO v3: remove this icon + Paste = "", + Search = "", + Selected = "❯", + Spellcheck = "暈", + TabClose = "", +} diff --git a/lua/core/icons/text.lua b/lua/core/icons/text.lua new file mode 100644 index 0000000..bc79218 --- /dev/null +++ b/lua/core/icons/text.lua @@ -0,0 +1,38 @@ +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 = "...", + FileModified = "*", + FileReadOnly = "[lock]", + FolderClosed = "[D]", + FolderEmpty = "[E]", + FolderOpen = "[O]", + GitAdd = "[+]", + GitChange = "[/]", + GitConflict = "[!]", + GitDelete = "[-]", + GitIgnored = "[I]", + GitRenamed = "[R]", + GitStaged = "[S]", + GitUnstaged = "[U]", + GitUntracked = "[?]", + MacroRecording = "Recording:", + NeovimClose = "X", -- TODO v3: remove this icon + Paste = "[PASTE]", + Search = "?", + Selected = "*", + Spellcheck = "[SPELL]", + TabClose = "X", +} diff --git a/lua/core/mappings.lua b/lua/core/mappings.lua new file mode 100644 index 0000000..21e6695 --- /dev/null +++ b/lua/core/mappings.lua @@ -0,0 +1,317 @@ +local is_available = astronvim.is_available + +local maps = { i = {}, n = {}, v = {}, t = {} } + +-- Normal -- +-- Standard Operations +maps.n["w"] = { "w", desc = "Save" } +maps.n["q"] = { "q", desc = "Quit" } +maps.n["h"] = { "nohlsearch", desc = "No Highlight" } -- TODO: REMOVE IN v3 +maps.n["fn"] = { "enew", desc = "New File" } +maps.n["gx"] = { function() astronvim.system_open() end, desc = "Open the file under cursor with system app" } +maps.n[""] = { "w!", desc = "Force write" } +maps.n[""] = { "q!", desc = "Force quit" } +maps.n["Q"] = "" +maps.n["|"] = { "vsplit", desc = "Vertical Split" } +maps.n["\\"] = { "split", desc = "Horizontal Split" } + +-- Packer +maps.n["pc"] = { "PackerCompile", desc = "Packer Compile" } +maps.n["pi"] = { "PackerInstall", desc = "Packer Install" } +maps.n["ps"] = { "PackerSync", desc = "Packer Sync" } +maps.n["pS"] = { "PackerStatus", desc = "Packer Status" } +maps.n["pu"] = { "PackerUpdate", desc = "Packer Update" } + +-- AstroNvim +maps.n["pa"] = { "AstroUpdatePackages", desc = "Update Packer and Mason" } +maps.n["pA"] = { "AstroUpdate", desc = "AstroNvim Update" } +maps.n["pv"] = { "AstroVersion", desc = "AstroNvim Version" } +maps.n["pl"] = { "AstroChangelog", desc = "AstroNvim Changelog" } + +-- Alpha +if is_available "alpha-nvim" then + maps.n["d"] = { function() require("alpha").start() end, desc = "Alpha Dashboard" } +end + +if vim.g.heirline_bufferline then + -- Manage Buffers + maps.n["c"] = { function() astronvim.close_buf(0) end, desc = "Close buffer" } + maps.n["C"] = { function() astronvim.close_buf(0, true) end, desc = "Force close buffer" } + maps.n[""] = { function() astronvim.nav_buf(vim.v.count > 0 and vim.v.count or 1) end, desc = "Next buffer" } + maps.n[""] = + { function() astronvim.nav_buf(-(vim.v.count > 0 and vim.v.count or 1)) end, desc = "Previous buffer" } + maps.n[">b"] = + { function() astronvim.move_buf(vim.v.count > 0 and vim.v.count or 1) end, desc = "Move buffer tab right" } + maps.n[" 0 and vim.v.count or 1)) end, desc = "Move buffer tab left" } + + maps.n["bb"] = { + function() + astronvim.status.heirline.buffer_picker(function(bufnr) vim.api.nvim_win_set_buf(0, bufnr) end) + end, + desc = "Select buffer from tabline", + } + maps.n["bd"] = { + function() + astronvim.status.heirline.buffer_picker(function(bufnr) astronvim.close_buf(bufnr) end) + end, + desc = "Delete buffer from tabline", + } + maps.n["b\\"] = { + function() + astronvim.status.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["b|"] = { + function() + astronvim.status.heirline.buffer_picker(function(bufnr) + vim.cmd.vsplit() + vim.api.nvim_win_set_buf(0, bufnr) + end) + end, + desc = "Vertical split buffer from tabline", + } +else -- TODO v3: remove this else block + -- Bufdelete + if is_available "bufdelete.nvim" then + maps.n["c"] = { function() require("bufdelete").bufdelete(0, false) end, desc = "Close buffer" } + maps.n["C"] = { function() require("bufdelete").bufdelete(0, true) end, desc = "Force close buffer" } + else + maps.n["c"] = { "bdelete", desc = "Close buffer" } + maps.n["C"] = { "bdelete!", desc = "Force close buffer" } + end + + -- Navigate buffers + if is_available "bufferline.nvim" then + maps.n[""] = { "BufferLineCycleNext", desc = "Next buffer tab" } + maps.n[""] = { "BufferLineCyclePrev", desc = "Previous buffer tab" } + maps.n[">b"] = { "BufferLineMoveNext", desc = "Move buffer tab right" } + maps.n["BufferLineMovePrev", desc = "Move buffer tab left" } + else + maps.n[""] = { "bnext", desc = "Next buffer" } + maps.n[""] = { "bprevious", desc = "Previous buffer" } + end +end + +-- Navigate tabs +maps.n["]t"] = { function() vim.cmd.tabnext() end, desc = "Next tab" } +maps.n["[t"] = { function() vim.cmd.tabprevious() end, desc = "Previous tab" } + +-- Comment +if is_available "Comment.nvim" then + maps.n["/"] = { function() require("Comment.api").toggle.linewise.current() end, desc = "Comment line" } + maps.v["/"] = { + "lua require('Comment.api').toggle.linewise(vim.fn.visualmode())", + desc = "Toggle comment line", + } +end + +-- GitSigns +if is_available "gitsigns.nvim" then + maps.n["gj"] = { function() require("gitsigns").next_hunk() end, desc = "Next Git hunk" } + maps.n["gk"] = { function() require("gitsigns").prev_hunk() end, desc = "Previous Git hunk" } + maps.n["gl"] = { function() require("gitsigns").blame_line() end, desc = "View Git blame" } + maps.n["gp"] = { function() require("gitsigns").preview_hunk() end, desc = "Preview Git hunk" } + maps.n["gh"] = { function() require("gitsigns").reset_hunk() end, desc = "Reset Git hunk" } + maps.n["gr"] = { function() require("gitsigns").reset_buffer() end, desc = "Reset Git buffer" } + maps.n["gs"] = { function() require("gitsigns").stage_hunk() end, desc = "Stage Git hunk" } + maps.n["gu"] = { function() require("gitsigns").undo_stage_hunk() end, desc = "Unstage Git hunk" } + maps.n["gd"] = { function() require("gitsigns").diffthis() end, desc = "View Git diff" } +end + +-- NeoTree +if is_available "neo-tree.nvim" then + maps.n["e"] = { "Neotree toggle", desc = "Toggle Explorer" } + maps.n["o"] = { "Neotree focus", desc = "Focus Explorer" } +end + +-- Session Manager +if is_available "neovim-session-manager" then + maps.n["Sl"] = { "SessionManager! load_last_session", desc = "Load last session" } + maps.n["Ss"] = { "SessionManager! save_current_session", desc = "Save this session" } + maps.n["Sd"] = { "SessionManager! delete_session", desc = "Delete session" } + maps.n["Sf"] = { "SessionManager! load_session", desc = "Search sessions" } + maps.n["S."] = + { "SessionManager! load_current_dir_session", desc = "Load current directory session" } +end + +-- Package Manager +if is_available "mason.nvim" then + maps.n["pI"] = { "Mason", desc = "Mason Installer" } + maps.n["pU"] = { "MasonUpdateAll", desc = "Mason Update" } +end + +-- Smart Splits +if is_available "smart-splits.nvim" then + -- Better window navigation + maps.n[""] = { function() require("smart-splits").move_cursor_left() end, desc = "Move to left split" } + maps.n[""] = { function() require("smart-splits").move_cursor_down() end, desc = "Move to below split" } + maps.n[""] = { function() require("smart-splits").move_cursor_up() end, desc = "Move to above split" } + maps.n[""] = { function() require("smart-splits").move_cursor_right() end, desc = "Move to right split" } + + -- Resize with arrows + maps.n[""] = { function() require("smart-splits").resize_up() end, desc = "Resize split up" } + maps.n[""] = { function() require("smart-splits").resize_down() end, desc = "Resize split down" } + maps.n[""] = { function() require("smart-splits").resize_left() end, desc = "Resize split left" } + maps.n[""] = { function() require("smart-splits").resize_right() end, desc = "Resize split right" } +else + maps.n[""] = { "h", desc = "Move to left split" } + maps.n[""] = { "j", desc = "Move to below split" } + maps.n[""] = { "k", desc = "Move to above split" } + maps.n[""] = { "l", desc = "Move to right split" } + maps.n[""] = { "resize -2", desc = "Resize split up" } + maps.n[""] = { "resize +2", desc = "Resize split down" } + maps.n[""] = { "vertical resize -2", desc = "Resize split left" } + maps.n[""] = { "vertical resize +2", desc = "Resize split right" } +end + +-- SymbolsOutline +if is_available "aerial.nvim" then + maps.n["lS"] = { function() require("aerial").toggle() end, desc = "Symbols outline" } +end + +-- Telescope +if is_available "telescope.nvim" then + maps.n["fw"] = { function() require("telescope.builtin").live_grep() end, desc = "Search words" } + maps.n["fW"] = { + function() + require("telescope.builtin").live_grep { + additional_args = function(args) return vim.list_extend(args, { "--hidden", "--no-ignore" }) end, + } + end, + desc = "Search words in all files", + } + maps.n["gt"] = { function() require("telescope.builtin").git_status() end, desc = "Git status" } + maps.n["gb"] = { function() require("telescope.builtin").git_branches() end, desc = "Git branches" } + maps.n["gc"] = { function() require("telescope.builtin").git_commits() end, desc = "Git commits" } + maps.n["ff"] = { function() require("telescope.builtin").find_files() end, desc = "Search files" } + maps.n["fF"] = { + function() require("telescope.builtin").find_files { hidden = true, no_ignore = true } end, + desc = "Search all files", + } + maps.n["fb"] = { function() require("telescope.builtin").buffers() end, desc = "Search buffers" } + maps.n["fh"] = { function() require("telescope.builtin").help_tags() end, desc = "Search help" } + maps.n["fm"] = { function() require("telescope.builtin").marks() end, desc = "Search marks" } + maps.n["fo"] = { function() require("telescope.builtin").oldfiles() end, desc = "Search history" } + maps.n["fc"] = + { function() require("telescope.builtin").grep_string() end, desc = "Search for word under cursor" } + maps.n["sb"] = { function() require("telescope.builtin").git_branches() end, desc = "Git branches" } + maps.n["sh"] = { function() require("telescope.builtin").help_tags() end, desc = "Search help" } + maps.n["sm"] = { function() require("telescope.builtin").man_pages() end, desc = "Search man" } + maps.n["sr"] = { function() require("telescope.builtin").registers() end, desc = "Search registers" } + maps.n["sk"] = { function() require("telescope.builtin").keymaps() end, desc = "Search keymaps" } + maps.n["sc"] = { function() require("telescope.builtin").commands() end, desc = "Search commands" } + if astronvim.is_available "nvim-notify" then + maps.n["sn"] = + { function() require("telescope").extensions.notify.notify() end, desc = "Search notifications" } + end + maps.n["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 symbols", + } + maps.n["lD"] = { function() require("telescope.builtin").diagnostics() end, desc = "Search diagnostics" } +end + +-- Terminal +if is_available "toggleterm.nvim" then + local toggle_term_cmd = astronvim.toggle_term_cmd + if vim.fn.executable "lazygit" == 1 then + maps.n["gg"] = { function() toggle_term_cmd "lazygit" end, desc = "ToggleTerm lazygit" } + maps.n["tl"] = { function() toggle_term_cmd "lazygit" end, desc = "ToggleTerm lazygit" } + end + if vim.fn.executable "node" == 1 then + maps.n["tn"] = { function() toggle_term_cmd "node" end, desc = "ToggleTerm node" } + end + if vim.fn.executable "gdu" == 1 then + maps.n["tu"] = { function() toggle_term_cmd "gdu" end, desc = "ToggleTerm gdu" } + end + if vim.fn.executable "btm" == 1 then + maps.n["tt"] = { function() toggle_term_cmd "btm" end, desc = "ToggleTerm btm" } + end + if vim.fn.executable "python" == 1 then + maps.n["tp"] = { function() toggle_term_cmd "python" end, desc = "ToggleTerm python" } + end + maps.n["tf"] = { "ToggleTerm direction=float", desc = "ToggleTerm float" } + maps.n["th"] = { "ToggleTerm size=10 direction=horizontal", desc = "ToggleTerm horizontal split" } + maps.n["tv"] = { "ToggleTerm size=80 direction=vertical", desc = "ToggleTerm vertical split" } + maps.n[""] = { "ToggleTerm", desc = "Toggle terminal" } + maps.t[""] = maps.n[""] + maps.n[""] = maps.n[""] + maps.t[""] = maps.n[""] +end + +if is_available "nvim-dap" then + -- 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 + maps.n[""] = { function() require("dap").continue() end, desc = "Debugger: Start" } + maps.n[""] = { function() require("dap").terminate() end, desc = "Debugger: Stop" } -- Shift+F5 + maps.n[""] = { function() require("dap").restart_frame() end, desc = "Debugger: Restart" } -- Control+F5 + maps.n[""] = { function() require("dap").pause() end, desc = "Debugger: Pause" } + maps.n[""] = { function() require("dap").toggle_breakpoint() end, desc = "Debugger: Toggle Breakpoint" } + maps.n[""] = { function() require("dap").step_over() end, desc = "Debugger: Step Over" } + maps.n[""] = { function() require("dap").step_into() end, desc = "Debugger: Step Into" } + maps.n[""] = { function() require("dap").step_out() end, desc = "Debugger: Step Out" } -- Shift+F11 + maps.n["Db"] = { function() require("dap").toggle_breakpoint() end, desc = "Toggle Breakpoint (F9)" } + maps.n["DB"] = { function() require("dap").clear_breakpoints() end, desc = "Clear Breakpoints" } + maps.n["Dc"] = { function() require("dap").continue() end, desc = "Start/Continue (F5)" } + maps.n["Di"] = { function() require("dap").step_into() end, desc = "Step Into (F11)" } + maps.n["Do"] = { function() require("dap").step_over() end, desc = "Step Over (F10)" } + maps.n["DO"] = { function() require("dap").step_out() end, desc = "Step Out (S-F11)" } + maps.n["Dq"] = { function() require("dap").close() end, desc = "Close Session" } + maps.n["DQ"] = { function() require("dap").terminate() end, desc = "Terminate Session (S-F5)" } + maps.n["Dp"] = { function() require("dap").pause() end, desc = "Pause (F6)" } + maps.n["Dr"] = { function() require("dap").restart_frame() end, desc = "Restart (C-F5)" } + maps.n["DR"] = { function() require("dap").repl.toggle() end, desc = "Toggle REPL" } + if is_available "nvim-dap-ui" then + maps.n["Du"] = { function() require("dapui").toggle() end, desc = "Toggle Debugger UI" } + maps.n["Dh"] = { function() require("dap.ui.widgets").hover() end, desc = "Debugger Hover" } + end +end + +-- Stay in indent mode +maps.v["<"] = { ""] = { ">gv", desc = "indent line" } + +-- Improved Terminal Navigation +maps.t[""] = { "h", desc = "Terminal left window navigation" } +maps.t[""] = { "j", desc = "Terminal down window navigation" } +maps.t[""] = { "k", desc = "Terminal up window navigation" } +maps.t[""] = { "l", desc = "Terminal right window navigation" } + +-- Custom menu for modification of the user experience +if is_available "nvim-autopairs" then + maps.n["ua"] = { function() astronvim.ui.toggle_autopairs() end, desc = "Toggle autopairs" } +end +maps.n["ub"] = { function() astronvim.ui.toggle_background() end, desc = "Toggle background" } +if is_available "nvim-cmp" then + maps.n["uc"] = { function() astronvim.ui.toggle_cmp() end, desc = "Toggle autocompletion" } +end +if is_available "nvim-colorizer.lua" then + maps.n["uC"] = { "ColorizerToggle", desc = "Toggle color highlight" } +end +maps.n["uS"] = { function() astronvim.ui.toggle_conceal() end, desc = "Toggle conceal" } +maps.n["ud"] = { function() astronvim.ui.toggle_diagnostics() end, desc = "Toggle diagnostics" } +maps.n["ug"] = { function() astronvim.ui.toggle_signcolumn() end, desc = "Toggle signcolumn" } +maps.n["ui"] = { function() astronvim.ui.set_indent() end, desc = "Change indent setting" } +maps.n["ul"] = { function() astronvim.ui.toggle_statusline() end, desc = "Toggle statusline" } +maps.n["un"] = { function() astronvim.ui.change_number() end, desc = "Change line numbering" } +maps.n["us"] = { function() astronvim.ui.toggle_spell() end, desc = "Toggle spellcheck" } +maps.n["up"] = { function() astronvim.ui.toggle_paste() end, desc = "Toggle paste mode" } +maps.n["ut"] = { function() astronvim.ui.toggle_tabline() end, desc = "Toggle tabline" } +maps.n["uu"] = { function() astronvim.ui.toggle_url_match() end, desc = "Toggle URL highlight" } +maps.n["uw"] = { function() astronvim.ui.toggle_wrap() end, desc = "Toggle wrap" } +maps.n["uy"] = { function() astronvim.ui.toggle_syntax() end, desc = "Toggle syntax highlight" } +maps.n["uN"] = { function() astronvim.ui.toggle_ui_notifications() end, desc = "Toggle UI notifications" } + +astronvim.set_mappings(astronvim.user_plugin_opts("mappings", maps)) diff --git a/lua/core/options.lua b/lua/core/options.lua new file mode 100644 index 0000000..ce2a54c --- /dev/null +++ b/lua/core/options.lua @@ -0,0 +1,72 @@ +vim.opt.shortmess:append { s = true, I = true } -- disable startup message +astronvim.vim_opts(astronvim.user_plugin_opts("options", { + opt = { + backspace = vim.opt.backspace + { "nostop" }, -- Don't stop backspace at insert + clipboard = "unnamedplus", -- Connection to the system clipboard + cmdheight = 0, -- hide command line unless needed + completeopt = { "menuone", "noselect" }, -- Options for insert mode completion + copyindent = true, -- Copy the previous indentation on autoindenting + cursorline = true, -- Highlight the text line of the cursor + expandtab = true, -- Enable the use of space in tab + fileencoding = "utf-8", -- File content encoding for the buffer + fillchars = { eob = " " }, -- Disable `~` on nonexistent lines + history = 100, -- Number of commands to remember in a history table + ignorecase = true, -- Case insensitive searching + laststatus = 3, -- globalstatus + mouse = "a", -- Enable mouse support + number = true, -- Show numberline + preserveindent = true, -- Preserve indent structure as much as possible + pumheight = 10, -- Height of the pop up menu + relativenumber = true, -- Show relative numberline + scrolloff = 8, -- Number of lines to keep above and below the cursor + shiftwidth = 2, -- Number of space inserted for indentation + showmode = false, -- Disable showing modes in command line + showtabline = 2, -- always display tabline + sidescrolloff = 8, -- Number of columns to keep at the sides of the cursor + signcolumn = "yes", -- Always show the sign column + smartcase = true, -- Case sensitivie searching + splitbelow = true, -- Splitting a new window below the current one + splitright = true, -- Splitting a new window at the right of the current one + tabstop = 2, -- Number of space in a tab + termguicolors = true, -- Enable 24-bit RGB color in the TUI + timeoutlen = 300, -- Length of time to wait for a mapped sequence + undofile = true, -- Enable persistent undo + updatetime = 300, -- Length of time to wait before triggering the plugin + wrap = false, -- Disable wrapping of lines longer than the width of window + writebackup = false, -- Disable making a backup before overwriting a file + }, + g = { + highlighturl_enabled = true, -- highlight URLs by default + mapleader = " ", -- set leader key + zipPlugin = false, -- disable zip + load_black = false, -- disable black + loaded_2html_plugin = true, -- disable 2html + loaded_getscript = true, -- disable getscript + loaded_getscriptPlugin = true, -- disable getscript + loaded_gzip = true, -- disable gzip + loaded_logipat = true, -- disable logipat + loaded_matchit = true, -- disable matchit + loaded_netrwFileHandlers = true, -- disable netrw + loaded_netrwPlugin = true, -- disable netrw + loaded_netrwSettngs = true, -- disable netrw + loaded_remote_plugins = true, -- disable remote plugins + loaded_tar = true, -- disable tar + loaded_tarPlugin = true, -- disable tar + loaded_zip = true, -- disable zip + loaded_zipPlugin = true, -- disable zip + loaded_vimball = true, -- disable vimball + loaded_vimballPlugin = true, -- disable vimball + autoformat_enabled = true, -- enable or disable auto formatting at start (lsp.formatting.format_on_save must be enabled) + lsp_handlers_enabled = true, -- enable or disable default vim.lsp.handlers (hover and signatureHelp) + cmp_enabled = true, -- enable completion at start + autopairs_enabled = true, -- enable autopairs at start + diagnostics_enabled = true, -- enable diagnostics at start + status_diagnostics_enabled = true, -- enable diagnostics in statusline + icons_enabled = true, -- disable icons in the UI (disable if no nerd font is available) + ui_notifications_enabled = true, -- disable notifications when toggling UI elements + heirline_bufferline = false, -- enable heirline bufferline (TODO v3: remove this option and make it default) + }, + t = { + bufs = vim.tbl_filter(astronvim.is_valid_buffer, vim.api.nvim_list_bufs()), -- buffers in tab + }, +})) diff --git a/lua/core/plugins.lua b/lua/core/plugins.lua new file mode 100644 index 0000000..330a466 --- /dev/null +++ b/lua/core/plugins.lua @@ -0,0 +1,375 @@ +local astro_plugins = { + -- Plugin manager + ["wbthomason/packer.nvim"] = { + setup = function() + astronvim.lazy_load_commands("packer.nvim", { + "PackerSnapshot", + "PackerSnapshotRollback", + "PackerSnapshotDelete", + "PackerInstall", + "PackerUpdate", + "PackerSync", + "PackerClean", + "PackerCompile", + "PackerStatus", + "PackerProfile", + "PackerLoad", + }) + end, + config = function() require "core.plugins" end, + }, + + -- Optimiser + ["lewis6991/impatient.nvim"] = {}, + + -- Lua functions + ["nvim-lua/plenary.nvim"] = { module = "plenary" }, + + -- Indent detection + ["Darazaki/indent-o-matic"] = { + opt = true, + setup = function() table.insert(astronvim.file_plugins, "indent-o-matic") end, + config = function() require "configs.indent-o-matic" end, + }, + + -- Notification Enhancer + ["rcarriga/nvim-notify"] = { + module = "notify", + setup = function() astronvim.load_plugin_with_func("nvim-notify", vim, "notify") end, + config = function() require "configs.notify" end, + }, + + -- Neovim UI Enhancer + ["stevearc/dressing.nvim"] = { + opt = true, + setup = function() astronvim.load_plugin_with_func("dressing.nvim", vim.ui, { "input", "select" }) end, + config = function() require "configs.dressing" end, + }, + + -- Smarter Splits + ["mrjones2014/smart-splits.nvim"] = { + module = "smart-splits", + config = function() require "configs.smart-splits" end, + }, + + -- Icons + ["nvim-tree/nvim-web-devicons"] = { + disable = not vim.g.icons_enabled, + module = "nvim-web-devicons", + config = function() require "configs.nvim-web-devicons" end, + }, + + -- LSP Icons + ["onsails/lspkind.nvim"] = { + disable = not vim.g.icons_enabled, + module = "lspkind", + config = function() require "configs.lspkind" end, + }, + + -- Bufferline + ["akinsho/bufferline.nvim"] = { -- TODO v3: remove this plugin + disable = vim.g.heirline_bufferline, + module = "bufferline", + event = "UIEnter", + config = function() require "configs.bufferline" end, + }, + + -- Better buffer closing + ["famiu/bufdelete.nvim"] = { + module = "bufdelete", + setup = function() astronvim.lazy_load_commands("bufdelete.nvim", { "Bdelete", "Bwipeout" }) end, + }, + + ["s1n7ax/nvim-window-picker"] = { + tag = "v1.*", + module = "window-picker", + config = function() require "configs.window-picker" end, + }, + + -- File explorer + ["nvim-neo-tree/neo-tree.nvim"] = { + branch = "v2.x", + module = "neo-tree", + requires = { { "MunifTanjim/nui.nvim", module = "nui" } }, + setup = function() + astronvim.lazy_load_commands("neo-tree.nvim", "Neotree") + vim.g.neo_tree_remove_legacy_commands = true + end, + config = function() require "configs.neo-tree" end, + }, + + -- Statusline + ["rebelot/heirline.nvim"] = { event = "VimEnter", config = function() require "configs.heirline" end }, + + -- Syntax highlighting + ["nvim-treesitter/nvim-treesitter"] = { + module = "nvim-treesitter", + setup = function() + table.insert(astronvim.file_plugins, "nvim-treesitter") + astronvim.lazy_load_commands("nvim-treesitter", { + "TSBufDisable", + "TSBufEnable", + "TSBufToggle", + "TSDisable", + "TSEnable", + "TSToggle", + "TSInstall", + "TSInstallInfo", + "TSInstallSync", + "TSModuleInfo", + "TSUninstall", + "TSUpdate", + "TSUpdateSync", + }) + end, + run = function() require("nvim-treesitter.install").update { with_sync = true }() end, + config = function() require "configs.treesitter" end, + }, + + -- Parenthesis highlighting + ["p00f/nvim-ts-rainbow"] = { after = "nvim-treesitter" }, + + -- Autoclose tags + ["windwp/nvim-ts-autotag"] = { after = "nvim-treesitter" }, + + -- Context based commenting + ["JoosepAlviste/nvim-ts-context-commentstring"] = { after = "nvim-treesitter" }, + + -- Snippet collection + ["rafamadriz/friendly-snippets"] = { opt = true }, + + -- Snippet engine + ["L3MON4D3/LuaSnip"] = { + module = "luasnip", + wants = "friendly-snippets", + config = function() require "configs.luasnip" end, + }, + + -- Completion engine + ["hrsh7th/nvim-cmp"] = { event = "InsertEnter", config = function() require "configs.cmp" end }, + + -- Snippet completion source + ["saadparwaiz1/cmp_luasnip"] = { + after = "nvim-cmp", + config = function() astronvim.add_user_cmp_source "luasnip" end, + }, + + -- Buffer completion source + ["hrsh7th/cmp-buffer"] = { after = "nvim-cmp", config = function() astronvim.add_user_cmp_source "buffer" end }, + + -- Path completion source + ["hrsh7th/cmp-path"] = { after = "nvim-cmp", config = function() astronvim.add_user_cmp_source "path" end }, + + -- LSP completion source + ["hrsh7th/cmp-nvim-lsp"] = { after = "nvim-cmp", config = function() astronvim.add_user_cmp_source "nvim_lsp" end }, + + -- Built-in LSP + ["neovim/nvim-lspconfig"] = { + module = "lspconfig", + setup = function() table.insert(astronvim.file_plugins, "nvim-lspconfig") end, + config = function() require "configs.lspconfig" end, + }, + + -- Formatting and linting + ["jose-elias-alvarez/null-ls.nvim"] = { + module = "null-ls", + setup = function() table.insert(astronvim.file_plugins, "null-ls.nvim") end, + config = function() require "configs.null-ls" end, + }, + + -- Debugger + ["mfussenegger/nvim-dap"] = { + disable = vim.fn.has "win32" == 1, + module = "dap", + config = function() require "configs.dap" end, + }, + + -- Debugger UI + ["rcarriga/nvim-dap-ui"] = { + disable = vim.fn.has "win32" == 1, + after = "nvim-dap", + config = function() require "configs.dapui" end, + }, + + -- Package Manager + ["williamboman/mason.nvim"] = { + module = "mason", + cmd = { + "Mason", + "MasonInstall", + "MasonUninstall", + "MasonUninstallAll", + "MasonLog", + "MasonUpdate", -- astronvim command + "MasonUpdateAll", -- astronvim command + }, + config = function() + require "configs.mason" + vim.tbl_map(function(plugin) pcall(require, plugin) end, { "lspconfig", "null-ls", "dap" }) + end, + }, + + -- LSP manager + ["williamboman/mason-lspconfig.nvim"] = { + after = "nvim-lspconfig", + config = function() require "configs.mason-lspconfig" end, + }, + + -- null-ls manager + ["jayp0521/mason-null-ls.nvim"] = { after = "null-ls.nvim", config = function() require "configs.mason-null-ls" end }, + + -- dap manager + ["jayp0521/mason-nvim-dap.nvim"] = { + disable = vim.fn.has "win32" == 1, + after = "nvim-dap", + config = function() require "configs.mason-nvim-dap" end, + }, + + -- LSP symbols + ["stevearc/aerial.nvim"] = { + module = "aerial", + after = { "nvim-treesitter", "nvim-lspconfig" }, + ft = { "man", "markdown" }, + config = function() require "configs.aerial" end, + }, + + -- Fuzzy finder + ["nvim-telescope/telescope.nvim"] = { + module = "telescope", + setup = function() astronvim.lazy_load_commands("telescope.nvim", "Telescope") end, + config = function() require "configs.telescope" end, + }, + + -- Fuzzy finder syntax support + ["nvim-telescope/telescope-fzf-native.nvim"] = { + after = "telescope.nvim", + disable = vim.fn.executable "make" == 0, + run = "make", + config = function() require("telescope").load_extension "fzf" end, + }, + + -- Git integration + ["lewis6991/gitsigns.nvim"] = { + disable = vim.fn.executable "git" == 0, + ft = "gitcommit", + setup = function() table.insert(astronvim.git_plugins, "gitsigns.nvim") end, + config = function() require "configs.gitsigns" end, + }, + + -- Start screen + ["goolord/alpha-nvim"] = { + module = "alpha", + setup = function() astronvim.lazy_load_commands("alpha-nvim", "Alpha") end, + config = function() require "configs.alpha" end, + }, + + -- Color highlighting + ["NvChad/nvim-colorizer.lua"] = { + opt = true, + setup = function() + astronvim.lazy_load_commands( + "nvim-colorizer.lua", + { "ColorizerToggle", "ColorizerAttachToBuffer", "ColorizerDetachFromBuffer", "ColorizerReloadAllBuffers" } + ) + table.insert(astronvim.file_plugins, "nvim-colorizer.lua") + end, + config = function() require "configs.colorizer" end, + }, + + -- Autopairs + ["windwp/nvim-autopairs"] = { event = "InsertEnter", config = function() require "configs.autopairs" end }, + + -- Terminal + ["akinsho/toggleterm.nvim"] = { + module = "toggleterm", + setup = function() astronvim.lazy_load_commands("toggleterm.nvim", { "ToggleTerm", "TermExec" }) end, + config = function() require "configs.toggleterm" end, + }, + + -- Commenting + ["numToStr/Comment.nvim"] = { + module = "Comment", + keys = { "gc", "gb" }, + config = function() require "configs.Comment" end, + }, + + -- Indentation + ["lukas-reineke/indent-blankline.nvim"] = { + opt = true, + setup = function() table.insert(astronvim.file_plugins, "indent-blankline.nvim") end, + config = function() require "configs.indent-line" end, + }, + + -- Keymaps popup + ["folke/which-key.nvim"] = { module = "which-key", config = function() require "configs.which-key" end }, + + -- Smooth escaping + ["max397574/better-escape.nvim"] = { + event = "InsertCharPre", + config = function() require "configs.better_escape" end, + }, + + -- Get extra JSON schemas + ["b0o/SchemaStore.nvim"] = { module = "schemastore" }, + + -- Session manager + ["Shatur/neovim-session-manager"] = { + module = "session_manager", + event = "BufWritePost", + setup = function() astronvim.lazy_load_commands("neovim-session-manager", "SessionManager") end, + config = function() require "configs.session_manager" end, + }, +} + +if astronvim.updater.snapshot then + for plugin, options in pairs(astro_plugins) do + local pin = astronvim.updater.snapshot[plugin:match "/([^/]*)$"] + if pin and pin.commit then + options.commit = pin.commit + options.tag = nil + end + end +end + +local user_plugin_opts = astronvim.user_plugin_opts +local status_ok, packer = pcall(require, "packer") +if status_ok then + packer.startup { + function(use) + local plugins = user_plugin_opts("plugins.init", astro_plugins) + for key, plugin in pairs(plugins) do + if type(key) == "string" and not plugin[1] then plugin[1] = key end + if key == "williamboman/mason.nvim" and plugin.cmd then + for mason_plugin, commands in pairs { -- lazy load mason plugin commands with Mason + ["jayp0521/mason-null-ls.nvim"] = { "NullLsInstall", "NullLsUninstall" }, + ["williamboman/mason-lspconfig.nvim"] = { "LspInstall", "LspUninstall" }, + ["jayp0521/mason-nvim-dap.nvim"] = { "DapInstall", "DapUninstall" }, + } do + if plugins[mason_plugin] and not plugins[mason_plugin].disable then + vim.list_extend(plugin.cmd, commands) + end + end + end + use(plugin) + end + end, + config = user_plugin_opts("plugins.packer", { + compile_path = astronvim.default_compile_path, + display = { + open_fn = function() return require("packer.util").float { border = "rounded" } end, + }, + profile = { + enable = true, + threshold = 0.0001, + }, + git = { + clone_timeout = 300, + subcommands = { + update = "pull --rebase", + }, + }, + auto_clean = true, + compile_on_sync = true, + }), + } +end diff --git a/lua/core/utils/git.lua b/lua/core/utils/git.lua new file mode 100644 index 0000000..125d296 --- /dev/null +++ b/lua/core/utils/git.lua @@ -0,0 +1,157 @@ +--- ### Git LUA API +-- +-- This module can be loaded with `local git = require "core.utils.git"` +-- +-- @module core.utils.git +-- @copyright 2022 +-- @license GNU General Public License v3.0 + +local git = { url = "https://github.com/" } + +--- Run a git command from the AstroNvim installation directory +-- @param args the git arguments +-- @return the result of the command or nil if unsuccessful +function git.cmd(args, ...) return astronvim.cmd("git -C " .. astronvim.install.home .. " " .. args, ...) end + +--- Check if the AstroNvim is able to reach the `git` command +-- @return the result of running `git --help` +function git.available() return vim.fn.executable "git" == 1 end + +--- Check if the AstroNvim home is a git repo +-- @return the result of the command +function git.is_repo() return git.cmd("rev-parse --is-inside-work-tree", false) end + +--- Fetch git remote +-- @param remote the remote to fetch +-- @return the result of the command +function git.fetch(remote, ...) return git.cmd("fetch " .. remote, ...) end + +--- Pull the git repo +-- @return the result of the command +function git.pull(...) return git.cmd("pull --rebase", ...) end + +--- Checkout git target +-- @param dest the target to checkout +-- @return the result of the command +function git.checkout(dest, ...) return git.cmd("checkout " .. dest, ...) end + +--- Hard reset to a git target +-- @param dest the target to hard reset to +-- @return the result of the command +function git.hard_reset(dest, ...) return git.cmd("reset --hard " .. dest, ...) end + +--- Check if a branch contains a commit +-- @param remote the git remote to check +-- @param branch the git branch to check +-- @param commit the git commit to check for +-- @return the result of the command +function git.branch_contains(remote, branch, commit, ...) + return git.cmd("merge-base --is-ancestor " .. commit .. " " .. remote .. "/" .. branch, ...) ~= nil +end + +--- Add a git remote +-- @param remote the remote to add +-- @param url the url of the remote +-- @return the result of the command +function git.remote_add(remote, url, ...) return git.cmd("remote add " .. remote .. " " .. url, ...) end + +--- Update a git remote URL +-- @param remote the remote to update +-- @param url the new URL of the remote +-- @return the result of the command +function git.remote_update(remote, url, ...) return git.cmd("remote set-url " .. remote .. " " .. url, ...) end + +--- Get the URL of a given git remote +-- @param remote the remote to get the URL of +-- @return the url of the remote +function git.remote_url(remote, ...) return astronvim.trim_or_nil(git.cmd("remote get-url " .. remote, ...)) end + +--- Get the current version with git describe including tags +-- @return the current git describe string +function git.current_version(...) return astronvim.trim_or_nil(git.cmd("describe --tags", ...)) end + +--- Get the current branch +-- @return the branch of the AstroNvim installation +function git.current_branch(...) return astronvim.trim_or_nil(git.cmd("rev-parse --abbrev-ref HEAD", ...)) end + +--- Get the current head of the git repo +-- @return the head string +function git.local_head(...) return astronvim.trim_or_nil(git.cmd("rev-parse HEAD", ...)) end + +--- Get the current head of a git remote +-- @param remote the remote to check +-- @param branch the branch to check +-- @return the head string of the remote branch +function git.remote_head(remote, branch, ...) + return astronvim.trim_or_nil(git.cmd("rev-list -n 1 " .. remote .. "/" .. branch, ...)) +end + +--- Get the commit hash of a given tag +-- @param tag the tag to resolve +-- @return the commit hash of a git tag +function git.tag_commit(tag, ...) return astronvim.trim_or_nil(git.cmd("rev-list -n 1 " .. tag, ...)) end + +--- Get the commit log between two commit hashes +-- @param start_hash the start commit hash +-- @param end_hash the end commit hash +-- @return an array like table of commit messages +function git.get_commit_range(start_hash, end_hash, ...) + local range = "" + if start_hash and end_hash then range = start_hash .. ".." .. end_hash end + local log = git.cmd('log --no-merges --pretty="format:[%h] %s" ' .. range, ...) + return log and vim.fn.split(log, "\n") or {} +end + +--- Get a list of all tags with a regex filter +-- @param search a regex to search the tags with (defaults to "v*" for version tags) +-- @return an array like table of tags that match the search +function git.get_versions(search, ...) + local tags = git.cmd('tag -l --sort=version:refname "' .. (search == "latest" and "v*" or search) .. '"', ...) + return tags and vim.fn.split(tags, "\n") or {} +end + +--- Get the latest version of a list of versions +-- @param versions a list of versions to search (defaults to all versions available) +-- @return the latest version from the array +function git.latest_version(versions, ...) + if not versions then versions = git.get_versions(...) end + return versions[#versions] +end + +--- Parse a remote url +-- @param str the remote to parse to a full git url +-- @return the full git url for the given remote string +function git.parse_remote_url(str) + return vim.fn.match(str, astronvim.url_matcher) == -1 + and git.url .. str .. (vim.fn.match(str, "/") == -1 and "/AstroNvim.git" or ".git") + or str +end + +--- Check if a Conventional Commit commit message is breaking or not +-- @param commit a commit message +-- @return boolean true if the message is breaking, false if the commit message is not breaking +function git.is_breaking(commit) return vim.fn.match(commit, "\\[.*\\]\\s\\+\\w\\+\\((\\w\\+)\\)\\?!:") ~= -1 end + +--- Get a list of breaking commits from commit messages using Conventional Commit standard +-- @param commits an array like table of commit messages +-- @return an array like table of commits that are breaking +function git.breaking_changes(commits) return vim.tbl_filter(git.is_breaking, commits) end + +--- Generate a table of commit messages for neovim's echo API with highlighting +-- @param commits an array like table of commit messages +-- @return an array like table of echo messages to provide to nvim_echo or astronvim.echo +function git.pretty_changelog(commits) + local changelog = {} + for _, commit in ipairs(commits) do + local hash, type, msg = commit:match "(%[.*%])(.*:)(.*)" + if hash and type and msg then + vim.list_extend( + changelog, + { { hash, "DiffText" }, { type, git.is_breaking(commit) and "DiffDelete" or "DiffChange" }, { msg }, { "\n" } } + ) + end + end + return changelog +end + +return git diff --git a/lua/core/utils/init.lua b/lua/core/utils/init.lua new file mode 100644 index 0000000..0ef452b --- /dev/null +++ b/lua/core/utils/init.lua @@ -0,0 +1,606 @@ +--- ### AstroNvim Utilities +-- +-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim` +-- +-- This module can also be manually loaded with `local astronvim = require "core.utils"` +-- +-- @module core.utils +-- @copyright 2022 +-- @license GNU General Public License v3.0 + +_G.astronvim = {} +local stdpath = vim.fn.stdpath +local tbl_insert = table.insert +local map = vim.keymap.set + +--- installation details from external installers +astronvim.install = astronvim_installation or { home = stdpath "config" } +--- external astronvim configuration folder +astronvim.install.config = stdpath("config"):gsub("nvim$", "astronvim") +vim.opt.rtp:append(astronvim.install.config) +local supported_configs = { astronvim.install.home, astronvim.install.config } + +--- Looks to see if a module path references a lua file in a configuration folder and tries to load it. If there is an error loading the file, write an error and continue +-- @param module the module path to try and load +-- @return the loaded module if successful or nil +local function load_module_file(module) + -- placeholder for final return value + local found_module = nil + -- search through each of the supported configuration locations + for _, config_path in ipairs(supported_configs) do + -- convert the module path to a file path (example user.init -> user/init.lua) + local module_path = config_path .. "/lua/" .. module:gsub("%.", "/") .. ".lua" + -- check if there is a readable file, if so, set it as found + if vim.fn.filereadable(module_path) == 1 then found_module = module_path end + end + -- if we found a readable lua file, try to load it + if found_module then + -- try to load the file + local status_ok, loaded_module = pcall(require, module) + -- if successful at loading, set the return variable + if status_ok then + found_module = loaded_module + -- if unsuccessful, throw an error + else + vim.api.nvim_err_writeln("Error loading file: " .. found_module .. "\n\n" .. loaded_module) + end + end + -- return the loaded module or nil if no file found + return found_module +end + +--- user settings from the base `user/init.lua` file +astronvim.user_settings = load_module_file "user.init" +--- default packer compilation location to be used in bootstrapping and packer setup call +astronvim.default_compile_path = stdpath "data" .. "/packer_compiled.lua" +--- table of user created terminals +astronvim.user_terminals = {} +--- table of plugins to load with git +astronvim.git_plugins = {} +--- table of plugins to load when file opened +astronvim.file_plugins = {} +--- regex used for matching a valid URL/URI string +astronvim.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]*})\\})+" + +--- Main configuration engine logic for extending a default configuration table with either a function override or a table to merge into the default option +-- @function astronvim.func_or_extend +-- @param overrides the override definition, either a table or a function that takes a single parameter of the original table +-- @param default the default configuration table +-- @param extend boolean value to either extend the default or simply overwrite it if an override is provided +-- @return the new configuration table +local function func_or_extend(overrides, default, extend) + -- if we want to extend the default with the provided override + if extend then + -- if the override is a table, use vim.tbl_deep_extend + if type(overrides) == "table" then + default = astronvim.default_tbl(overrides, default) + -- if the override is a function, call it with the default and overwrite default with the return value + elseif type(overrides) == "function" then + default = overrides(default) + end + -- if extend is set to false and we have a provided override, simply override the default + elseif overrides ~= nil then + default = overrides + end + -- return the modified default table + return default +end + +--- Merge extended options with a default table of options +-- @param opts the new options that should be merged with the default table +-- @param default the default table that you want to merge into +-- @return the merged table +function astronvim.default_tbl(opts, default) + opts = opts or {} + return default and vim.tbl_deep_extend("force", default, opts) or opts +end + +--- Call function if a condition is met +-- @param func the function to run +-- @param condition a boolean value of whether to run the function or not +function astronvim.conditional_func(func, condition, ...) + -- if the condition is true or no condition is provided, evaluate the function with the rest of the parameters and return the result + if (condition == nil or condition) and type(func) == "function" then return func(...) end +end + +--- Get highlight properties for a given highlight name +-- @param name highlight group name +-- @return table of highlight group properties +function astronvim.get_hlgroup(name, fallback) + if vim.fn.hlexists(name) == 1 then + local hl = vim.api.nvim_get_hl_by_name(name, vim.o.termguicolors) + if not hl["foreground"] then hl["foreground"] = "NONE" end + if not hl["background"] then hl["background"] = "NONE" end + hl.fg, hl.bg, hl.sp = hl.foreground, hl.background, hl.special + hl.ctermfg, hl.ctermbg = hl.foreground, hl.background + return hl + end + return fallback +end + +--- Trim a string or return nil +-- @param str the string to trim +-- @return a trimmed version of the string or nil if the parameter isn't a string +function astronvim.trim_or_nil(str) return type(str) == "string" and vim.trim(str) or nil end + +--- Add left and/or right padding to a string +-- @param str the string to add padding to +-- @param padding a table of the format `{ left = 0, right = 0}` that defines the number of spaces to include to the left and the right of the string +-- @return the padded string +function astronvim.pad_string(str, padding) + padding = padding or {} + return str and str ~= "" and string.rep(" ", padding.left or 0) .. str .. string.rep(" ", padding.right or 0) or "" +end + +--- Initialize icons used throughout the user interface +function astronvim.initialize_icons() + astronvim.icons = astronvim.user_plugin_opts("icons", require "core.icons.nerd_font") + astronvim.text_icons = astronvim.user_plugin_opts("text_icons", require "core.icons.text") +end + +--- Get an icon from `lspkind` if it is available and return it +-- @param kind the kind of icon in `lspkind` to retrieve +-- @return the icon +function astronvim.get_icon(kind) + local icon_pack = vim.g.icons_enabled and "icons" or "text_icons" + if not astronvim[icon_pack] then astronvim.initialize_icons() end + return astronvim[icon_pack] and astronvim[icon_pack][kind] or "" +end + +--- Serve a notification with a title of AstroNvim +-- @param msg the notification body +-- @param type the type of the notification (:help vim.log.levels) +-- @param opts table of nvim-notify options to use (:help notify-options) +function astronvim.notify(msg, type, opts) + vim.schedule(function() vim.notify(msg, type, astronvim.default_tbl(opts, { title = "AstroNvim" })) end) +end + +--- Trigger an AstroNvim user event +-- @param event the event name to be appended to Astro +function astronvim.event(event) + vim.schedule(function() vim.api.nvim_exec_autocmds("User", { pattern = "Astro" .. event }) end) +end + +--- Wrapper function for neovim echo API +-- @param messages an array like table where each item is an array like table of strings to echo +function astronvim.echo(messages) + -- if no parameter provided, echo a new line + messages = messages or { { "\n" } } + if type(messages) == "table" then vim.api.nvim_echo(messages, false, {}) end +end + +--- Echo a message and prompt the user for yes or no response +-- @param messages the message to echo +-- @return True if the user responded y, False for any other response +function astronvim.confirm_prompt(messages) + if messages then astronvim.echo(messages) end + local confirmed = string.lower(vim.fn.input "(y/n) ") == "y" + astronvim.echo() + astronvim.echo() + return confirmed +end + +--- Search the user settings (user/init.lua table) for a table with a module like path string +-- @param module the module path like string to look up in the user settings table +-- @return the value of the table entry if exists or nil +local function user_setting_table(module) + -- get the user settings table + local settings = astronvim.user_settings or {} + -- iterate over the path string split by '.' to look up the table value + for tbl in string.gmatch(module, "([^%.]+)") do + settings = settings[tbl] + -- if key doesn't exist, keep the nil value and stop searching + if settings == nil then break end + end + -- return the found settings + return settings +end + +--- Check if packer is installed and loadable, if not then install it and make sure it loads +function astronvim.initialize_packer() + -- try loading packer + local packer_path = stdpath "data" .. "/site/pack/packer/opt/packer.nvim" + local packer_avail = vim.fn.empty(vim.fn.glob(packer_path)) == 0 + -- if packer isn't availble, reinstall it + if not packer_avail then + -- set the location to install packer + -- delete the old packer install if one exists + vim.fn.delete(packer_path, "rf") + -- clone packer + vim.fn.system { + "git", + "clone", + "--depth", + "1", + "https://github.com/wbthomason/packer.nvim", + packer_path, + } + -- add packer and try loading it + vim.cmd.packadd "packer.nvim" + local packer_loaded, _ = pcall(require, "packer") + packer_avail = packer_loaded + -- if packer didn't load, print error + if not packer_avail then vim.api.nvim_err_writeln("Failed to load packer at:" .. packer_path) end + end + -- if packer is available, check if there is a compiled packer file + if packer_avail then + -- try to load the packer compiled file + local run_me, _ = loadfile( + astronvim.user_plugin_opts("plugins.packer", { compile_path = astronvim.default_compile_path }).compile_path + ) + if run_me then + -- if the file loads, run the compiled function + run_me() + else + -- if there is no compiled file, ask user to sync packer + require "core.plugins" + vim.api.nvim_create_autocmd("User", { + once = true, + pattern = "PackerComplete", + callback = function() + vim.cmd.bw() + vim.tbl_map(require, { "nvim-treesitter", "mason" }) + astronvim.notify "Mason is installing packages if configured, check status with :Mason" + end, + }) + vim.opt.cmdheight = 1 + vim.notify "Please wait while plugins are installed..." + vim.cmd.PackerSync() + end + end +end + +function astronvim.lazy_load_commands(plugin, commands) + if type(commands) == "string" then commands = { commands } end + if astronvim.is_available(plugin) and not packer_plugins[plugin].loaded then + for _, command in ipairs(commands) do + pcall( + vim.cmd, + string.format( + 'command -nargs=* -range -bang -complete=file %s lua require("packer.load")({"%s"}, { cmd = "%s", l1 = , l2 = , bang = , args = , mods = "" }, _G.packer_plugins)', + command, + plugin, + command + ) + ) + end + end +end + +--- Set vim options with a nested table like API with the format vim... +-- @param options the nested table of vim options +function astronvim.vim_opts(options) + for scope, table in pairs(options) do + for setting, value in pairs(table) do + vim[scope][setting] = value + end + end +end + +--- User configuration entry point to override the default options of a configuration table with a user configuration file or table in the user/init.lua user settings +-- @param module the module path of the override setting +-- @param default the default settings that will be overridden +-- @param extend boolean value to either extend the default settings or overwrite them with the user settings entirely (default: true) +-- @param prefix a module prefix for where to search (default: user) +-- @return the new configuration settings with the user overrides applied +function astronvim.user_plugin_opts(module, default, extend, prefix) + -- default to extend = true + if extend == nil then extend = true end + -- if no default table is provided set it to an empty table + default = default or {} + -- try to load a module file if it exists + local user_settings = load_module_file((prefix or "user") .. "." .. module) + -- if no user module file is found, try to load an override from the user settings table from user/init.lua + if user_settings == nil and prefix == nil then user_settings = user_setting_table(module) end + -- if a user override was found call the configuration engine + if user_settings ~= nil then default = func_or_extend(user_settings, default, extend) end + -- return the final configuration table with any overrides applied + return default +end + +--- Open a URL under the cursor with the current operating system (Supports Mac OS X and *nix) +-- @param path the path of the file to open with the system opener +function astronvim.system_open(path) + path = path or vim.fn.expand "" + if vim.fn.has "mac" == 1 then + -- if mac use the open command + vim.fn.jobstart({ "open", path }, { detach = true }) + elseif vim.fn.has "unix" == 1 then + -- if unix then use xdg-open + vim.fn.jobstart({ "xdg-open", path }, { detach = true }) + else + -- if any other operating system notify the user that there is currently no support + astronvim.notify("System open is not supported on this OS!", "error") + end +end + +-- term_details can be either a string for just a command or +-- a complete table to provide full access to configuration when calling Terminal:new() + +--- Toggle a user terminal if it exists, if not then create a new one and save it +-- @param term_details a terminal command string or a table of options for Terminal:new() (Check toggleterm.nvim documentation for table format) +function astronvim.toggle_term_cmd(opts) + local terms = astronvim.user_terminals + -- if a command string is provided, create a basic table for Terminal:new() options + if type(opts) == "string" then opts = { cmd = opts, hidden = true } end + local num = vim.v.count > 0 and vim.v.count or 1 + -- if terminal doesn't exist yet, create it + if not terms[opts.cmd] then terms[opts.cmd] = {} end + if not terms[opts.cmd][num] then + if not opts.count then opts.count = vim.tbl_count(terms) * 100 + num end + terms[opts.cmd][num] = require("toggleterm.terminal").Terminal:new(opts) + end + -- toggle the terminal + astronvim.user_terminals[opts.cmd][num]:toggle() +end + +--- Add a source to cmp +-- @param source the cmp source string or table to add (see cmp documentation for source table format) +function astronvim.add_cmp_source(source) + -- load cmp if available + local cmp_avail, cmp = pcall(require, "cmp") + if cmp_avail then + -- get the current cmp config + local config = cmp.get_config() + -- add the source to the list of sources + tbl_insert(config.sources, source) + -- call the setup function again + cmp.setup(config) + end +end + +--- Get the priority of a cmp source +-- @param source the cmp source string or table (see cmp documentation for source table format) +-- @return a cmp source table with the priority set from the user configuration +function astronvim.get_user_cmp_source(source) + -- if the source is a string, convert it to a cmp source table + source = type(source) == "string" and { name = source } or source + -- get the priority of the source name from the user configuration + local priority = astronvim.user_plugin_opts("cmp.source_priority", { + nvim_lsp = 1000, + luasnip = 750, + buffer = 500, + path = 250, + })[source.name] + -- if a priority is found, set it in the source + if priority then source.priority = priority end + -- return the source table + return source +end + +--- add a source to cmp with the user configured priority +-- @param source a cmp source string or table (see cmp documentation for source table format) +function astronvim.add_user_cmp_source(source) astronvim.add_cmp_source(astronvim.get_user_cmp_source(source)) end + +--- register mappings table with which-key +-- @param mappings nested table of mappings where the first key is the mode, the second key is the prefix, and the value is the mapping table for which-key +-- @param opts table of which-key options when setting the mappings (see which-key documentation for possible values) +function astronvim.which_key_register(mappings, opts) + local status_ok, which_key = pcall(require, "which-key") + if not status_ok then return end + for mode, prefixes in pairs(mappings) do + for prefix, mapping_table in pairs(prefixes) do + which_key.register( + mapping_table, + astronvim.default_tbl(opts, { + mode = mode, + prefix = prefix, + buffer = nil, + silent = true, + noremap = true, + nowait = true, + }) + ) + end + end +end + +--- Get a list of registered null-ls providers for a given filetype +-- @param filetype the filetype to search null-ls for +-- @return a list of null-ls sources +function astronvim.null_ls_providers(filetype) + local registered = {} + -- try to load null-ls + local sources_avail, sources = pcall(require, "null-ls.sources") + if sources_avail then + -- get the available sources of a given filetype + for _, source in ipairs(sources.get_available(filetype)) do + -- get each source name + for method in pairs(source.methods) do + registered[method] = registered[method] or {} + tbl_insert(registered[method], source.name) + end + end + end + -- return the found null-ls sources + return registered +end + +--- Get the null-ls sources for a given null-ls method +-- @param filetype the filetype to search null-ls for +-- @param method the null-ls method (check null-ls documentation for available methods) +-- @return the available sources for the given filetype and method +function astronvim.null_ls_sources(filetype, method) + local methods_avail, methods = pcall(require, "null-ls.methods") + return methods_avail and astronvim.null_ls_providers(filetype)[methods.internal[method]] or {} +end + +--- Create a button entity to use with the alpha dashboard +-- @param sc the keybinding string to convert to a button +-- @param txt the explanation text of what the keybinding does +-- @return a button entity table for an alpha configuration +function astronvim.alpha_button(sc, txt) + -- replace in shortcut text with LDR for nicer printing + local sc_ = sc:gsub("%s", ""):gsub("LDR", "") + -- if the leader is set, replace the text with the actual leader key for nicer printing + if vim.g.mapleader then sc = sc:gsub("LDR", vim.g.mapleader == " " and "SPC" or vim.g.mapleader) end + -- return the button entity to display the correct text and send the correct keybinding on press + return { + type = "button", + val = txt, + on_press = function() + local key = vim.api.nvim_replace_termcodes(sc_, true, false, true) + vim.api.nvim_feedkeys(key, "normal", false) + end, + opts = { + position = "center", + text = txt, + shortcut = sc, + cursor = 5, + width = 36, + align_shortcut = "right", + hl = "DashboardCenter", + hl_shortcut = "DashboardShortcut", + }, + } +end + +--- Check if a plugin is defined in packer. Useful with lazy loading when a plugin is not necessarily loaded yet +-- @param plugin the plugin string to search for +-- @return boolean value if the plugin is available +function astronvim.is_available(plugin) return packer_plugins ~= nil and packer_plugins[plugin] ~= nil end + +--- A helper function to wrap a module function to require a plugin before running +-- @param plugin the plugin string to call `require("packer").laoder` with +-- @param module the system module where the functions live (e.g. `vim.ui`) +-- @param func_names a string or a list like table of strings for functions to wrap in the given moduel (e.g. `{ "ui", "select }`) +function astronvim.load_plugin_with_func(plugin, module, func_names) + if type(func_names) == "string" then func_names = { func_names } end + for _, func in ipairs(func_names) do + local old_func = module[func] + module[func] = function(...) + module[func] = old_func + require("packer").loader(plugin) + module[func](...) + end + end +end + +--- Table based API for setting keybindings +-- @param map_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 A base set of options to set on every keybinding +function astronvim.set_mappings(map_table, base) + -- iterate over the first keys for each mode + 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 or {} + if type(options) == "table" then + cmd = options[1] + keymap_opts = vim.tbl_deep_extend("force", options, keymap_opts) + keymap_opts[1] = nil + end + -- extend the keybinding options with the base provided and set the mapping + map(mode, keymap, cmd, keymap_opts) + end + end + end +end + +--- Delete the syntax matching rules for URLs/URIs if set +function astronvim.delete_url_match() + for _, match in ipairs(vim.fn.getmatches()) do + if match.group == "HighlightURL" then vim.fn.matchdelete(match.id) end + end +end + +--- Add syntax matching rules for highlighting URLs/URIs +function astronvim.set_url_match() + astronvim.delete_url_match() + if vim.g.highlighturl_enabled then vim.fn.matchadd("HighlightURL", astronvim.url_matcher, 15) end +end + +--- Run a shell command and capture the output and if the command succeeded or failed +-- @param cmd the terminal command to execute +-- @param show_error boolean of whether or not to show an unsuccessful command as an error to the user +-- @return the result of a successfully executed command or nil +function astronvim.cmd(cmd, show_error) + if vim.fn.has "win32" == 1 then cmd = { "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 and true or show_error) then + vim.api.nvim_err_writeln("Error running command: " .. cmd .. "\nError message:\n" .. result) + end + return success and result:gsub("[\27\155][][()#;?%d]*[A-PRZcf-ntqry=><~]", "") or nil +end + +--- Check if a buffer is valid +-- @param bufnr the buffer to check +-- @return true if the buffer is valid or false +function astronvim.is_valid_buffer(bufnr) + if not bufnr or bufnr < 1 then return false end + return vim.bo[bufnr].buflisted and vim.api.nvim_buf_is_valid(bufnr) +end + +--- Move the current buffer tab n places in the bufferline +-- @param n numer of tabs to move the current buffer over by (positive = right, negative = left) +function astronvim.move_buf(n) + if n == 0 then return end -- if n = 0 then no shifts are needed + local bufs = vim.t.bufs -- make temp variable + for i, bufnr in ipairs(bufs) do -- loop to find current buffer + if bufnr == vim.api.nvim_get_current_buf() then -- found index of current buffer + for _ = 0, (n % #bufs) - 1 do -- calculate number of right shifts + local new_i = i + 1 -- get next i + if i == #bufs then -- if at end, cycle to beginning + new_i = 1 -- next i is actually 1 if at the end + local val = bufs[i] -- save value + table.remove(bufs, i) -- remove from end + table.insert(bufs, new_i, val) -- insert at beginning + else -- if not at the end,then just do an in place swap + bufs[i], bufs[new_i] = bufs[new_i], bufs[i] + end + i = new_i -- iterate i to next value + end + break + end + end + vim.t.bufs = bufs -- set buffers + vim.cmd.redrawtabline() -- redraw tabline +end + +--- Navigate left and right by n places in the bufferline +-- @param n the number of tabs to navigate to (positive = right, negative = left) +function astronvim.nav_buf(n) + local current = vim.api.nvim_get_current_buf() + for i, v in ipairs(vim.t.bufs) do + if current == v then + vim.cmd.b(vim.t.bufs[(i + n - 1) % #vim.t.bufs + 1]) + break + end + end +end + +--- Close a given buffer +-- @param bufnr? the buffer number to close or the current buffer if not provided +function astronvim.close_buf(bufnr, force) + if force == nil then force = false end + local current = vim.api.nvim_get_current_buf() + if not bufnr or bufnr == 0 then bufnr = current end + if bufnr == current then astronvim.nav_buf(-1) end + + if astronvim.is_available "bufdelete.nvim" then + require("bufdelete").bufdelete(bufnr, force) + else + vim.cmd((force and "bd!" or "confirm bd") .. bufnr) + end +end + +--- Close the current tab +function astronvim.close_tab() + if #vim.api.nvim_list_tabpages() > 1 then + vim.t.bufs = nil + vim.cmd.tabclose() + end +end + +require "core.utils.ui" +require "core.utils.status" +require "core.utils.updater" +require "core.utils.mason" +require "core.utils.lsp" + +return astronvim diff --git a/lua/core/utils/lsp.lua b/lua/core/utils/lsp.lua new file mode 100644 index 0000000..6987266 --- /dev/null +++ b/lua/core/utils/lsp.lua @@ -0,0 +1,243 @@ +--- ### AstroNvim LSP +-- +-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim.lsp` +-- +-- This module can also be manually loaded with `local updater = require("core.utils").lsp` +-- +-- @module core.utils.lsp +-- @see core.utils +-- @copyright 2022 +-- @license GNU General Public License v3.0 + +astronvim.lsp = {} +local tbl_contains = vim.tbl_contains +local tbl_isempty = vim.tbl_isempty +local user_plugin_opts = astronvim.user_plugin_opts +local conditional_func = astronvim.conditional_func +local is_available = astronvim.is_available +local user_registration = user_plugin_opts("lsp.server_registration", nil, false) +local skip_setup = user_plugin_opts "lsp.skip_setup" + +astronvim.lsp.formatting = + astronvim.user_plugin_opts("lsp.formatting", { format_on_save = { enabled = true }, disabled = {} }) +if type(astronvim.lsp.formatting.format_on_save) == "boolean" then + astronvim.lsp.formatting.format_on_save = { enabled = astronvim.lsp.formatting.format_on_save } +end + +astronvim.lsp.format_opts = vim.deepcopy(astronvim.lsp.formatting) +astronvim.lsp.format_opts.disabled = nil +astronvim.lsp.format_opts.format_on_save = nil +astronvim.lsp.format_opts.filter = function(client) + local filter = astronvim.lsp.formatting.filter + local disabled = astronvim.lsp.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 + +--- Helper function to set up a given server with the Neovim LSP client +-- @param server the name of the server to be setup +astronvim.lsp.setup = function(server) + if not tbl_contains(skip_setup, server) then + -- if server doesn't exist, set it up from user server definition + if not pcall(require, "lspconfig.server_configurations." .. server) then + local server_definition = user_plugin_opts("lsp.server-settings." .. server) + if server_definition.cmd then require("lspconfig.configs")[server] = { default_config = server_definition } end + end + local opts = astronvim.lsp.server_settings(server) + if type(user_registration) == "function" then + user_registration(server, opts) + else + require("lspconfig")[server].setup(opts) + end + end +end + +--- The `on_attach` function used by AstroNvim +-- @param client the LSP client details when attaching +-- @param bufnr the number of the buffer that the LSP client is attaching to +astronvim.lsp.on_attach = function(client, bufnr) + local capabilities = client.server_capabilities + local lsp_mappings = { + n = { + ["ld"] = { function() vim.diagnostic.open_float() end, desc = "Hover diagnostics" }, + ["[d"] = { function() vim.diagnostic.goto_prev() end, desc = "Previous diagnostic" }, + ["]d"] = { function() vim.diagnostic.goto_next() end, desc = "Next diagnostic" }, + ["gl"] = { function() vim.diagnostic.open_float() end, desc = "Hover diagnostics" }, + }, + v = {}, + } + + if is_available "mason-lspconfig.nvim" then + lsp_mappings.n["li"] = { "LspInfo", desc = "LSP information" } + end + + if is_available "null-ls.nvim" then + lsp_mappings.n["lI"] = { "NullLsInfo", desc = "Null-ls information" } + end + + if capabilities.codeActionProvider then + lsp_mappings.n["la"] = { function() vim.lsp.buf.code_action() end, desc = "LSP code action" } + lsp_mappings.v["la"] = lsp_mappings.n["la"] + end + + if capabilities.codeLensProvider then + lsp_mappings.n["ll"] = { function() vim.lsp.codelens.refresh() end, desc = "LSP codelens refresh" } + lsp_mappings.n["lL"] = { function() vim.lsp.codelens.run() end, desc = "LSP codelens run" } + end + + if capabilities.declarationProvider then + lsp_mappings.n["gD"] = { function() vim.lsp.buf.declaration() end, desc = "Declaration of current symbol" } + end + + if capabilities.definitionProvider then + lsp_mappings.n["gd"] = { function() vim.lsp.buf.definition() end, desc = "Show the definition of current symbol" } + end + + if capabilities.documentFormattingProvider and not tbl_contains(astronvim.lsp.formatting.disabled, client.name) then + lsp_mappings.n["lf"] = { + function() vim.lsp.buf.format(astronvim.lsp.format_opts) end, + desc = "Format buffer", + } + lsp_mappings.v["lf"] = lsp_mappings.n["lf"] + + vim.api.nvim_buf_create_user_command( + bufnr, + "Format", + function() vim.lsp.buf.format(astronvim.lsp.format_opts) end, + { desc = "Format file with LSP" } + ) + local autoformat = astronvim.lsp.formatting.format_on_save + local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype") + if + autoformat.enabled + and (tbl_isempty(autoformat.allow_filetypes or {}) or tbl_contains(autoformat.allow_filetypes, filetype)) + and (tbl_isempty(autoformat.ignore_filetypes or {}) or not tbl_contains(autoformat.ignore_filetypes, filetype)) + then + local autocmd_group = "auto_format_" .. bufnr + vim.api.nvim_create_augroup(autocmd_group, { clear = true }) + vim.api.nvim_create_autocmd("BufWritePre", { + group = autocmd_group, + buffer = bufnr, + desc = "Auto format buffer " .. bufnr .. " before save", + callback = function() + if vim.g.autoformat_enabled then + vim.lsp.buf.format(astronvim.default_tbl({ bufnr = bufnr }, astronvim.lsp.format_opts)) + end + end, + }) + lsp_mappings.n["uf"] = { + function() astronvim.ui.toggle_autoformat() end, + desc = "Toggle autoformatting", + } + end + end + + if capabilities.documentHighlightProvider then + local highlight_name = vim.fn.printf("lsp_document_highlight_%d", bufnr) + vim.api.nvim_create_augroup(highlight_name, {}) + vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, { + group = highlight_name, + buffer = bufnr, + callback = function() vim.lsp.buf.document_highlight() end, + }) + vim.api.nvim_create_autocmd("CursorMoved", { + group = highlight_name, + buffer = bufnr, + callback = function() vim.lsp.buf.clear_references() end, + }) + end + + if capabilities.hoverProvider then + lsp_mappings.n["K"] = { function() vim.lsp.buf.hover() end, desc = "Hover symbol details" } + end + + if capabilities.implementationProvider then + lsp_mappings.n["gI"] = { function() vim.lsp.buf.implementation() end, desc = "Implementation of current symbol" } + end + + if capabilities.referencesProvider then + lsp_mappings.n["gr"] = { function() vim.lsp.buf.references() end, desc = "References of current symbol" } + lsp_mappings.n["lR"] = { function() vim.lsp.buf.references() end, desc = "Search references" } + end + + if capabilities.renameProvider then + lsp_mappings.n["lr"] = { function() vim.lsp.buf.rename() end, desc = "Rename current symbol" } + end + + if capabilities.signatureHelpProvider then + lsp_mappings.n["lh"] = { function() vim.lsp.buf.signature_help() end, desc = "Signature help" } + end + + if capabilities.typeDefinitionProvider then + lsp_mappings.n["gT"] = { function() vim.lsp.buf.type_definition() end, desc = "Definition of current type" } + end + + if capabilities.workspaceSymbolProvider then + lsp_mappings.n["lG"] = { function() vim.lsp.buf.workspace_symbol() end, desc = "Search workspace symbols" } + end + + 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["lR"] then + lsp_mappings.n["lR"][1] = function() require("telescope.builtin").lsp_references() end + end + if lsp_mappings.n.gT then + lsp_mappings.n.gT[1] = function() require("telescope.builtin").lsp_type_definitions() end + end + if lsp_mappings.n["lG"] then + lsp_mappings.n["lG"][1] = function() require("telescope.builtin").lsp_workspace_symbols() end + end + end + + astronvim.set_mappings(user_plugin_opts("lsp.mappings", lsp_mappings), { buffer = bufnr }) + if not vim.tbl_isempty(lsp_mappings.v) then + astronvim.which_key_register({ v = { [""] = { l = { name = "LSP" } } } }, { buffer = bufnr }) + end + + local on_attach_override = user_plugin_opts("lsp.on_attach", nil, false) + conditional_func(on_attach_override, true, client, bufnr) +end + +--- The default AstroNvim LSP capabilities +astronvim.lsp.capabilities = vim.lsp.protocol.make_client_capabilities() +astronvim.lsp.capabilities.textDocument.completion.completionItem.documentationFormat = { "markdown", "plaintext" } +astronvim.lsp.capabilities.textDocument.completion.completionItem.snippetSupport = true +astronvim.lsp.capabilities.textDocument.completion.completionItem.preselectSupport = true +astronvim.lsp.capabilities.textDocument.completion.completionItem.insertReplaceSupport = true +astronvim.lsp.capabilities.textDocument.completion.completionItem.labelDetailsSupport = true +astronvim.lsp.capabilities.textDocument.completion.completionItem.deprecatedSupport = true +astronvim.lsp.capabilities.textDocument.completion.completionItem.commitCharactersSupport = true +astronvim.lsp.capabilities.textDocument.completion.completionItem.tagSupport = { valueSet = { 1 } } +astronvim.lsp.capabilities.textDocument.completion.completionItem.resolveSupport = { + properties = { "documentation", "detail", "additionalTextEdits" }, +} +astronvim.lsp.capabilities = user_plugin_opts("lsp.capabilities", astronvim.lsp.capabilities) +astronvim.lsp.flags = user_plugin_opts "lsp.flags" + +--- Get the server settings for a given language server to be provided to the server's `setup()` call +-- @param server_name the name of the server +-- @return the table of LSP options used when setting up the given language server +function astronvim.lsp.server_settings(server_name) + local server = require("lspconfig")[server_name] + local opts = user_plugin_opts( -- get user server-settings + "lsp.server-settings." .. server_name, -- TODO: RENAME lsp.server-settings to lsp.config in v3 + user_plugin_opts("server-settings." .. server_name, { -- get default server-settings + capabilities = vim.tbl_deep_extend("force", astronvim.lsp.capabilities, server.capabilities or {}), + flags = vim.tbl_deep_extend("force", astronvim.lsp.flags, server.flags or {}), + }, true, "configs") + ) + local old_on_attach = server.on_attach + local user_on_attach = opts.on_attach + opts.on_attach = function(client, bufnr) + conditional_func(old_on_attach, true, client, bufnr) + astronvim.lsp.on_attach(client, bufnr) + conditional_func(user_on_attach, true, client, bufnr) + end + return opts +end + +return astronvim.lsp diff --git a/lua/core/utils/mason.lua b/lua/core/utils/mason.lua new file mode 100644 index 0000000..3c3d9ad --- /dev/null +++ b/lua/core/utils/mason.lua @@ -0,0 +1,95 @@ +--- ### AstroNvim Mason Utils +-- +-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim.mason` +-- +-- This module can also be manually loaded with `local updater = require("core.utils").mason` +-- +-- @module core.utils.mason +-- @see core.utils +-- @copyright 2022 +-- @license GNU General Public License v3.0 + +astronvim.mason = {} + +--- Update a mason package +-- @param pkg_name string of the name of the package as defined in Mason (Not mason-lspconfig or mason-null-ls) +-- @param auto_install boolean of whether or not to install a package that is not currently installed (default: True) +function astronvim.mason.update(pkg_name, auto_install) + if auto_install == nil then auto_install = true end + local registry_avail, registry = pcall(require, "mason-registry") + if not registry_avail then + vim.api.nvim_err_writeln "Unable to access mason registry" + return + end + + local pkg_avail, pkg = pcall(registry.get_package, pkg_name) + if not pkg_avail then + astronvim.notify(("Mason: %s is not available"):format(pkg_name), "error") + else + if not pkg:is_installed() then + if auto_install then + astronvim.notify(("Mason: Installing %s"):format(pkg.name)) + pkg:install() + else + astronvim.notify(("Mason: %s not installed"):format(pkg.name), "warn") + end + else + pkg:check_new_version(function(update_available, version) + if update_available then + astronvim.notify(("Mason: Updating %s to %s"):format(pkg.name, version.latest_version)) + pkg:install():on("closed", function() astronvim.notify(("Mason: Updated %s"):format(pkg.name)) end) + else + astronvim.notify(("Mason: No updates available for %s"):format(pkg.name)) + end + end) + end + end +end + +--- Update all packages in Mason +function astronvim.mason.update_all() + local registry_avail, registry = pcall(require, "mason-registry") + if not registry_avail then + vim.api.nvim_err_writeln "Unable to access mason registry" + return + end + + local installed_pkgs = registry.get_installed_packages() + local running = #installed_pkgs + local no_pkgs = running == 0 + astronvim.notify "Mason: Checking for package updates..." + + if no_pkgs then + astronvim.notify "Mason: No updates available" + astronvim.event "MasonUpdateComplete" + else + local updated = false + for _, pkg in ipairs(installed_pkgs) do + pkg:check_new_version(function(update_available, version) + if update_available then + updated = true + astronvim.notify(("Mason: Updating %s to %s"):format(pkg.name, version.latest_version)) + pkg:install():on("closed", function() + running = running - 1 + if running == 0 then + astronvim.notify "Mason: Update Complete" + astronvim.event "MasonUpdateComplete" + end + end) + else + running = running - 1 + if running == 0 then + if updated then + astronvim.notify "Mason: Update Complete" + else + astronvim.notify "Mason: No updates available" + end + astronvim.event "MasonUpdateComplete" + end + end + end) + end + end +end + +return astronvim.mason diff --git a/lua/core/utils/status.lua b/lua/core/utils/status.lua new file mode 100644 index 0000000..84f97cf --- /dev/null +++ b/lua/core/utils/status.lua @@ -0,0 +1,1216 @@ +--- ### AstroNvim Status +-- +-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim.status` +-- +-- This module can also be manually loaded with `local status = require "core.utils.status"` +-- +-- @module core.utils.status +-- @copyright 2022 +-- @license GNU General Public License v3.0 +astronvim.status = { hl = {}, init = {}, provider = {}, condition = {}, component = {}, utils = {}, env = {} } + +astronvim.status.env.modes = { + ["n"] = { "NORMAL", "normal" }, + ["no"] = { "OP", "normal" }, + ["nov"] = { "OP", "normal" }, + ["noV"] = { "OP", "normal" }, + ["no"] = { "OP", "normal" }, + ["niI"] = { "NORMAL", "normal" }, + ["niR"] = { "NORMAL", "normal" }, + ["niV"] = { "NORMAL", "normal" }, + ["i"] = { "INSERT", "insert" }, + ["ic"] = { "INSERT", "insert" }, + ["ix"] = { "INSERT", "insert" }, + ["t"] = { "TERM", "terminal" }, + ["nt"] = { "TERM", "terminal" }, + ["v"] = { "VISUAL", "visual" }, + ["vs"] = { "VISUAL", "visual" }, + ["V"] = { "LINES", "visual" }, + ["Vs"] = { "LINES", "visual" }, + [""] = { "BLOCK", "visual" }, + ["s"] = { "BLOCK", "visual" }, + ["R"] = { "REPLACE", "replace" }, + ["Rc"] = { "REPLACE", "replace" }, + ["Rx"] = { "REPLACE", "replace" }, + ["Rv"] = { "V-REPLACE", "replace" }, + ["s"] = { "SELECT", "visual" }, + ["S"] = { "SELECT", "visual" }, + [""] = { "BLOCK", "visual" }, + ["c"] = { "COMMAND", "command" }, + ["cv"] = { "COMMAND", "command" }, + ["ce"] = { "COMMAND", "command" }, + ["r"] = { "PROMPT", "inactive" }, + ["rm"] = { "MORE", "inactive" }, + ["r?"] = { "CONFIRM", "inactive" }, + ["!"] = { "SHELL", "inactive" }, + ["null"] = { "null", "inactive" }, +} + +astronvim.status.env.separators = astronvim.user_plugin_opts("heirline.separators", { + none = { "", "" }, + left = { "", " " }, + right = { " ", "" }, + center = { " ", " " }, + tab = { "", " " }, +}) + +astronvim.status.env.attributes = astronvim.user_plugin_opts("heirline.attributes", { + buffer_active = { bold = true, italic = true }, + buffer_picker = { bold = true }, + macro_recording = { bold = true }, + git_branch = { bold = true }, + git_diff = { bold = true }, +}) + +astronvim.status.env.icon_highlights = astronvim.user_plugin_opts("heirline.icon_highlights", { + file_icon = { + tabline = function(self) return self.is_active or self.is_visible end, + statusline = true, + }, +}) + +local function pattern_match(str, pattern_list) + for _, pattern in ipairs(pattern_list) do + if str:find(pattern) then return true end + end + return false +end + +astronvim.status.env.buf_matchers = { + filetype = function(pattern_list, bufnr) return pattern_match(vim.bo[bufnr or 0].filetype, pattern_list) end, + buftype = function(pattern_list, bufnr) return pattern_match(vim.bo[bufnr or 0].buftype, pattern_list) end, + bufname = function(pattern_list, bufnr) + return pattern_match(vim.fn.fnamemodify(vim.api.nvim_buf_get_name(bufnr or 0), ":t"), pattern_list) + end, +} + +--- Get the highlight background color of the lualine theme for the current colorscheme +-- @param mode the neovim mode to get the color of +-- @param fallback the color to fallback on if a lualine theme is not present +-- @return The background color of the lualine theme or the fallback parameter if one doesn't exist +function astronvim.status.hl.lualine_mode(mode, fallback) + local lualine_avail, lualine = pcall(require, "lualine.themes." .. (vim.g.colors_name or "default_theme")) + local lualine_opts = lualine_avail and lualine[mode] + return lualine_opts and type(lualine_opts.a) == "table" and lualine_opts.a.bg or fallback +end + +--- Get the highlight for the current mode +-- @return the highlight group for the current mode +-- @usage local heirline_component = { provider = "Example Provider", hl = astronvim.status.hl.mode }, +function astronvim.status.hl.mode() return { bg = astronvim.status.hl.mode_bg() } end + +--- Get the foreground color group for the current mode, good for usage with Heirline surround utility +-- @return the highlight group for the current mode foreground +-- @usage local heirline_component = require("heirline.utils").surround({ "|", "|" }, astronvim.status.hl.mode_bg, heirline_component), + +function astronvim.status.hl.mode_bg() return astronvim.status.env.modes[vim.fn.mode()][2] end + +--- Get the foreground color group for the current filetype +-- @return the highlight group for the current filetype foreground +-- @usage local heirline_component = { provider = astronvim.status.provider.fileicon(), hl = astronvim.status.hl.filetype_color }, +function astronvim.status.hl.filetype_color(self) + local devicons_avail, devicons = pcall(require, "nvim-web-devicons") + if not devicons_avail then return {} end + local _, color = devicons.get_icon_color( + vim.fn.fnamemodify(vim.api.nvim_buf_get_name(self and self.bufnr or 0), ":t"), + nil, + { default = true } + ) + return { fg = color } +end + +--- Merge the color and attributes from user settings for a given name +-- @param name string, the name of the element to get the attributes and colors for +-- @param include_bg boolean whether or not to include background color (Default: false) +-- @return a table of highlight information +-- @usage local heirline_component = { provider = "Example Provider", hl = astronvim.status.hl.get_attributes("treesitter") }, +function astronvim.status.hl.get_attributes(name, include_bg) + local hl = astronvim.status.env.attributes[name] or {} + hl.fg = name .. "_fg" + if include_bg then hl.bg = name .. "_bg" end + return hl +end + +--- Enable filetype color highlight if enabled in icon_highlights.file_icon options +-- @param name string of the icon_highlights.file_icon table element +-- @return function for setting hl property in a component +-- @usage local heirline_component = { provider = "Example Provider", hl = astronvim.status.hl.file_icon("winbar") }, +function astronvim.status.hl.file_icon(name) + return function(self) + local hl_enabled = astronvim.status.env.icon_highlights.file_icon[name] + if type(hl_enabled) == "function" then hl_enabled = hl_enabled(self) end + if hl_enabled then return astronvim.status.hl.filetype_color(self) end + end +end + +--- An `init` function to build a set of children components for LSP breadcrumbs +-- @param opts options for configuring the breadcrumbs (default: `{ separator = " > ", icon = { enabled = true, hl = false }, padding = { left = 0, right = 0 } }`) +-- @return The Heirline init function +-- @usage local heirline_component = { init = astronvim.status.init.breadcrumbs { padding = { left = 1 } } } +function astronvim.status.init.breadcrumbs(opts) + opts = astronvim.default_tbl(opts, { + separator = " > ", + icon = { enabled = true, hl = astronvim.status.env.icon_highlights.breadcrumbs }, + padding = { left = 0, right = 0 }, + }) + return function(self) + local data = require("aerial").get_location(true) or {} + local children = {} + -- create a child for each level + for i, d in ipairs(data) do + local pos = astronvim.status.utils.encode_pos(d.lnum, d.col, self.winnr) + local child = { + { provider = string.gsub(d.name, "%%", "%%%%"):gsub("%s*->%s*", "") }, -- add symbol name + on_click = { -- add on click function + minwid = pos, + callback = function(_, minwid) + local lnum, col, winnr = astronvim.status.utils.decode_pos(minwid) + vim.api.nvim_win_set_cursor(vim.fn.win_getid(winnr), { lnum, col }) + end, + name = "heirline_breadcrumbs", + }, + } + if opts.icon.enabled then -- add icon and highlight if enabled + local hl = opts.icon.hl + if type(hl) == "function" then hl = hl(self) end + table.insert(child, 1, { + provider = string.format("%s ", d.icon), + hl = hl and string.format("Aerial%sIcon", d.kind) or nil, + }) + end + if #data > 1 and i < #data then table.insert(child, { provider = opts.separator }) end -- add a separator only if needed + table.insert(children, child) + end + if opts.padding.left > 0 then -- add left padding + table.insert(children, 1, { provider = astronvim.pad_string(" ", { left = opts.padding.left - 1 }) }) + end + if opts.padding.right > 0 then -- add right padding + table.insert(children, { provider = astronvim.pad_string(" ", { right = opts.padding.right - 1 }) }) + end + -- instantiate the new child + self[1] = self:new(children, 1) + end +end + +--- An `init` function to build multiple update events which is not supported yet by Heirline's update field +-- @param opts an array like table of autocmd events as either just a string or a table with custom patterns and callbacks. +-- @return The Heirline init function +-- @usage local heirline_component = { init = astronvim.status.init.update_events { "BufEnter", { "User", pattern = "LspProgressUpdate" } } } +function astronvim.status.init.update_events(opts) + return function(self) + if not rawget(self, "once") then + local clear_cache = function() self._win_cache = nil end + for _, event in ipairs(opts) do + local event_opts = { callback = clear_cache } + if type(event) == "table" then + event_opts.pattern = event.pattern + event_opts.callback = event.callback or clear_cache + event.pattern = nil + event.callback = nil + end + vim.api.nvim_create_autocmd(event, event_opts) + end + self.once = true + end + end +end + +--- A provider function for the fill string +-- @return the statusline string for filling the empty space +-- @usage local heirline_component = { provider = astronvim.status.provider.fill } +function astronvim.status.provider.fill() return "%=" end + +--- A provider function for the current tab numbre +-- @return the statusline function to return a string for a tab number +-- @usage local heirline_component = { provider = astronvim.status.provider.tabnr() } +function astronvim.status.provider.tabnr() + return function(self) return (self and self.tabnr) and "%" .. self.tabnr .. "T " .. self.tabnr .. " %T" or "" end +end + +--- A provider function for showing if spellcheck is on +-- @param opts options passed to the stylize function +-- @return the function for outputting if spell is enabled +-- @usage local heirline_component = { provider = astronvim.status.provider.spell() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.spell(opts) + opts = astronvim.default_tbl(opts, { str = "", icon = { kind = "Spellcheck" }, show_empty = true }) + return function() return astronvim.status.utils.stylize(vim.wo.spell and opts.str, opts) end +end + +--- A provider function for showing if paste is enabled +-- @param opts options passed to the stylize function +-- @return the function for outputting if paste is enabled + +-- @usage local heirline_component = { provider = astronvim.status.provider.paste() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.paste(opts) + opts = astronvim.default_tbl(opts, { str = "", icon = { kind = "Paste" }, show_empty = true }) + return function() return astronvim.status.utils.stylize(vim.opt.paste:get() and opts.str, opts) end +end + +--- A provider function for displaying if a macro is currently being recorded +-- @param opts a prefix before the recording register and options passed to the stylize function +-- @return a function that returns a string of the current recording status +-- @usage local heirline_component = { provider = astronvim.status.provider.macro_recording() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.macro_recording(opts) + opts = astronvim.default_tbl(opts, { prefix = "@" }) + return function() + local register = vim.fn.reg_recording() + if register ~= "" then register = opts.prefix .. register end + return astronvim.status.utils.stylize(register, opts) + end +end + +--- A provider function for displaying the current search count +-- @param opts options for `vim.fn.searchcount` and options passed to the stylize function +-- @return a function that returns a string of the current search location +-- @usage local heirline_component = { provider = astronvim.status.provider.search_count() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.search_count(opts) + local search_func = vim.tbl_isempty(opts or {}) and function() return vim.fn.searchcount() end + or function() return vim.fn.searchcount(opts) end + return function() + local search_ok, search = pcall(search_func) + if search_ok and type(search) == "table" and search.total then + return astronvim.status.utils.stylize( + string.format( + "%s%d/%s%d", + search.current > search.maxcount and ">" or "", + math.min(search.current, search.maxcount), + search.incomplete == 2 and ">" or "", + math.min(search.total, search.maxcount) + ), + opts + ) + end + end +end + +--- A provider function for showing the text of the current vim mode +-- @param opts options for padding the text and options passed to the stylize function +-- @return the function for displaying the text of the current vim mode +-- @usage local heirline_component = { provider = astronvim.status.provider.mode_text() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.mode_text(opts) + local max_length = + math.max(unpack(vim.tbl_map(function(str) return #str[1] end, vim.tbl_values(astronvim.status.env.modes)))) + return function() + local text = astronvim.status.env.modes[vim.fn.mode()][1] + if opts.pad_text then + local padding = max_length - #text + if opts.pad_text == "right" then + text = string.rep(" ", padding) .. text + elseif opts.pad_text == "left" then + text = text .. string.rep(" ", padding) + elseif opts.pad_text == "center" then + text = string.rep(" ", math.floor(padding / 2)) .. text .. string.rep(" ", math.ceil(padding / 2)) + end + end + return astronvim.status.utils.stylize(text, opts) + end +end + +--- A provider function for showing the percentage of the current location in a document +-- @param opts options for Top/Bot text, fixed width, and options passed to the stylize function +-- @return the statusline string for displaying the percentage of current document location +-- @usage local heirline_component = { provider = astronvim.status.provider.percentage() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.percentage(opts) + opts = astronvim.default_tbl(opts, { fixed_width = false, edge_text = true }) + return function() + local text = "%" .. (opts.fixed_width and "3" or "") .. "p%%" + if opts.edge_text then + local current_line = vim.fn.line "." + if current_line == 1 then + text = (opts.fixed_width and " " or "") .. "Top" + elseif current_line == vim.fn.line "$" then + text = (opts.fixed_width and " " or "") .. "Bot" + end + end + return astronvim.status.utils.stylize(text, opts) + end +end + +--- A provider function for showing the current line and character in a document +-- @param opts options for padding the line and character locations and options passed to the stylize function +-- @return the statusline string for showing location in document line_num:char_num +-- @usage local heirline_component = { provider = astronvim.status.provider.ruler({ pad_ruler = { line = 3, char = 2 } }) } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.ruler(opts) + opts = astronvim.default_tbl(opts, { pad_ruler = { line = 0, char = 0 } }) + local padding_str = string.format("%%%dd:%%%dd", opts.pad_ruler.line, opts.pad_ruler.char) + return function() + local line = vim.fn.line "." + local char = vim.fn.virtcol "." + return astronvim.status.utils.stylize(string.format(padding_str, line, char), opts) + end +end + +--- A provider function for showing the current location as a scrollbar +-- @param opts options passed to the stylize function +-- @return the function for outputting the scrollbar +-- @usage local heirline_component = { provider = astronvim.status.provider.scrollbar() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.scrollbar(opts) + local sbar = { "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" } + return function() + local curr_line = vim.api.nvim_win_get_cursor(0)[1] + local lines = vim.api.nvim_buf_line_count(0) + local i = math.floor((curr_line - 1) / lines * #sbar) + 1 + return astronvim.status.utils.stylize(string.rep(sbar[i], 2), opts) + end +end + +--- A provider to simply show a cloes button icon +-- @param opts options passed to the stylize function and the kind of icon to use +-- @return return the stylized icon +-- @usage local heirline_component = { provider = astronvim.status.provider.close_button() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.close_button(opts) + opts = astronvim.default_tbl(opts, { kind = "BufferClose" }) + return astronvim.status.utils.stylize(astronvim.get_icon(opts.kind), opts) +end + +--- A provider function for showing the current filetype +-- @param opts options passed to the stylize function +-- @return the function for outputting the filetype +-- @usage local heirline_component = { provider = astronvim.status.provider.filetype() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.filetype(opts) + return function(self) + local buffer = vim.bo[self and self.bufnr or 0] + return astronvim.status.utils.stylize(string.lower(buffer.filetype), opts) + end +end + +--- A provider function for showing the current filename +-- @param opts options for argument to fnamemodify to format filename and options passed to the stylize function +-- @return the function for outputting the filename +-- @usage local heirline_component = { provider = astronvim.status.provider.filename() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.filename(opts) + opts = astronvim.default_tbl( + opts, + { fallback = "[No Name]", fname = function(nr) return vim.api.nvim_buf_get_name(nr) end, modify = ":t" } + ) + return function(self) + local filename = vim.fn.fnamemodify(opts.fname(self and self.bufnr or 0), opts.modify) + return astronvim.status.utils.stylize((filename == "" and opts.fallback or filename), opts) + end +end + +--- Get a unique filepath between all buffers +-- @param opts options for function to get the buffer name, a buffer number, max length, and options passed to the stylize function +-- @return path to file that uniquely identifies each buffer +-- @usage local heirline_component = { provider = astronvim.status.provider.unique_path() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.unique_path(opts) + opts = astronvim.default_tbl(opts, { + buf_name = function(bufnr) return vim.fn.fnamemodify(vim.api.nvim_buf_get_name(bufnr), ":t") end, + bufnr = 0, + max_length = 16, + }) + return function(self) + opts.bufnr = self and self.bufnr or opts.bufnr + local name = opts.buf_name(opts.bufnr) + local unique_path = "" + -- check for same buffer names under different dirs + -- TODO v3: remove get_valid_buffers + for _, value in ipairs(vim.g.heirline_bufferline and vim.t.bufs or astronvim.status.utils.get_valid_buffers()) do + if name == opts.buf_name(value) and value ~= opts.bufnr then + local other = {} + for match in (vim.api.nvim_buf_get_name(value) .. "/"):gmatch("(.-)" .. "/") do + table.insert(other, match) + end + + local current = {} + for match in (vim.api.nvim_buf_get_name(opts.bufnr) .. "/"):gmatch("(.-)" .. "/") do + table.insert(current, match) + end + + unique_path = "" + + for i = #current - 1, 1, -1 do + local value_current = current[i] + local other_current = other[i] + + if value_current ~= other_current then + unique_path = value_current .. "/" + break + end + end + break + end + end + return astronvim.status.utils.stylize( + ( + opts.max_length > 0 + and #unique_path > opts.max_length + and string.sub(unique_path, 1, opts.max_length - 2) .. astronvim.get_icon "Ellipsis" .. "/" + ) or unique_path, + opts + ) + end +end + +--- A provider function for showing if the current file is modifiable +-- @param opts options passed to the stylize function +-- @return the function for outputting the indicator if the file is modified +-- @usage local heirline_component = { provider = astronvim.status.provider.file_modified() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.file_modified(opts) + opts = astronvim.default_tbl(opts, { str = "", icon = { kind = "FileModified" }, show_empty = true }) + return function(self) + return astronvim.status.utils.stylize( + astronvim.status.condition.file_modified((self or {}).bufnr) and opts.str, + opts + ) + end +end + +--- A provider function for showing if the current file is read-only +-- @param opts options passed to the stylize function +-- @return the function for outputting the indicator if the file is read-only +-- @usage local heirline_component = { provider = astronvim.status.provider.file_read_only() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.file_read_only(opts) + opts = astronvim.default_tbl(opts, { str = "", icon = { kind = "FileReadOnly" }, show_empty = true }) + return function(self) + return astronvim.status.utils.stylize( + astronvim.status.condition.file_read_only((self or {}).bufnr) and opts.str, + opts + ) + end +end + +--- A provider function for showing the current filetype icon +-- @param opts options passed to the stylize function +-- @return the function for outputting the filetype icon +-- @usage local heirline_component = { provider = astronvim.status.provider.file_icon() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.file_icon(opts) + return function(self) + local devicons_avail, devicons = pcall(require, "nvim-web-devicons") + if not devicons_avail then return "" end + local ft_icon, _ = devicons.get_icon( + vim.fn.fnamemodify(vim.api.nvim_buf_get_name(self and self.bufnr or 0), ":t"), + nil, + { default = true } + ) + return astronvim.status.utils.stylize(ft_icon, opts) + end +end + +--- A provider function for showing the current git branch +-- @param opts options passed to the stylize function +-- @return the function for outputting the git branch +-- @usage local heirline_component = { provider = astronvim.status.provider.git_branch() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.git_branch(opts) + return function(self) return astronvim.status.utils.stylize(vim.b[self and self.bufnr or 0].gitsigns_head or "", opts) end +end + +--- A provider function for showing the current git diff count of a specific type +-- @param opts options for type of git diff and options passed to the stylize function +-- @return the function for outputting the git diff +-- @usage local heirline_component = { provider = astronvim.status.provider.git_diff({ type = "added" }) } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.git_diff(opts) + if not opts or not opts.type then return end + return function(self) + local status = vim.b[self and self.bufnr or 0].gitsigns_status_dict + return astronvim.status.utils.stylize( + status and status[opts.type] and status[opts.type] > 0 and tostring(status[opts.type]) or "", + opts + ) + end +end + +--- A provider function for showing the current diagnostic count of a specific severity +-- @param opts options for severity of diagnostic and options passed to the stylize function +-- @return the function for outputting the diagnostic count +-- @usage local heirline_component = { provider = astronvim.status.provider.diagnostics({ severity = "ERROR" }) } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.diagnostics(opts) + if not opts or not opts.severity then return end + return function(self) + local bufnr = self and self.bufnr or 0 + local count = #vim.diagnostic.get(bufnr, opts.severity and { severity = vim.diagnostic.severity[opts.severity] }) + return astronvim.status.utils.stylize(count ~= 0 and tostring(count) or "", opts) + end +end + +--- A provider function for showing the current progress of loading language servers +-- @param opts options passed to the stylize function +-- @return the function for outputting the LSP progress +-- @usage local heirline_component = { provider = astronvim.status.provider.lsp_progress() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.lsp_progress(opts) + return function() + local Lsp = vim.lsp.util.get_progress_messages()[1] + local function escape(str) return string.gsub(str, "%%2F", "/") end + return astronvim.status.utils.stylize( + Lsp + and string.format( + " %%<%s %s %s (%s%%%%) ", + astronvim.get_icon("LSP" .. ((Lsp.percentage or 0) >= 70 and { "Loaded", "Loaded", "Loaded" } or { + "Loading1", + "Loading2", + "Loading3", + })[math.floor(vim.loop.hrtime() / 12e7) % 3 + 1]), + Lsp.title and escape(Lsp.title) or "", + Lsp.message and escape(Lsp.message) or "", + Lsp.percentage or 0 + ) + or "", + opts + ) + end +end + +--- A provider function for showing the connected LSP client names +-- @param opts options for explanding null_ls clients, max width percentage, and options passed to the stylize function +-- @return the function for outputting the LSP client names +-- @usage local heirline_component = { provider = astronvim.status.provider.lsp_client_names({ expand_null_ls = true, truncate = 0.25 }) } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.lsp_client_names(opts) + opts = astronvim.default_tbl(opts, { expand_null_ls = true, truncate = 0.25 }) + return function(self) + local buf_client_names = {} + for _, client in pairs(vim.lsp.get_active_clients { bufnr = self and self.bufnr or 0 }) do + if client.name == "null-ls" and opts.expand_null_ls then + local null_ls_sources = {} + for _, type in ipairs { "FORMATTING", "DIAGNOSTICS" } do + for _, source in ipairs(astronvim.null_ls_sources(vim.bo.filetype, type)) do + null_ls_sources[source] = true + end + end + vim.list_extend(buf_client_names, vim.tbl_keys(null_ls_sources)) + else + table.insert(buf_client_names, client.name) + end + end + local str = table.concat(buf_client_names, ", ") + if type(opts.truncate) == "number" then + local max_width = math.floor(astronvim.status.utils.width() * opts.truncate) + if #str > max_width then str = string.sub(str, 0, max_width) .. "…" end + end + return astronvim.status.utils.stylize(str, opts) + end +end + +--- A provider function for showing if treesitter is connected +-- @param opts options passed to the stylize function +-- @return the function for outputting TS if treesitter is connected +-- @usage local heirline_component = { provider = astronvim.status.provider.treesitter_status() } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.treesitter_status(opts) + return function() + return astronvim.status.utils.stylize(require("nvim-treesitter.parser").has_parser() and "TS" or "", opts) + end +end + +--- A provider function for displaying a single string +-- @param opts options passed to the stylize function +-- @return the stylized statusline string +-- @usage local heirline_component = { provider = astronvim.status.provider.str({ str = "Hello" }) } +-- @see astronvim.status.utils.stylize +function astronvim.status.provider.str(opts) + opts = astronvim.default_tbl(opts, { str = " " }) + return astronvim.status.utils.stylize(opts.str, opts) +end + +--- A condition function if the window is currently active +-- @return boolean of wether or not the window is currently actie +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.is_active } +function astronvim.status.condition.is_active() return vim.api.nvim_get_current_win() == tonumber(vim.g.actual_curwin) end + +--- A condition function if the buffer filetype,buftype,bufname match a pattern +-- @param patterns the table of patterns to match +-- @param bufnr number of the buffer to match (Default: 0 [current]) +-- @return boolean of wether or not LSP is attached +-- @usage local heirline_component = { provider = "Example Provider", condition = function() return astronvim.status.condition.buffer_matches { buftype = { "terminal" } } end } +function astronvim.status.condition.buffer_matches(patterns, bufnr) + for kind, pattern_list in pairs(patterns) do + if astronvim.status.env.buf_matchers[kind](pattern_list, bufnr) then return true end + end + return false +end + +--- A condition function if a macro is being recorded +-- @return boolean of wether or not a macro is currently being recorded +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.is_macro_recording } +function astronvim.status.condition.is_macro_recording() return vim.fn.reg_recording() ~= "" end + +--- A condition function if search is visible +-- @return boolean of wether or not searching is currently visible +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.is_hlsearch } +function astronvim.status.condition.is_hlsearch() return vim.v.hlsearch ~= 0 end + +--- A condition function if the current file is in a git repo +-- @param bufnr a buffer number to check the condition for, a table with bufnr property, or nil to get the current buffer +-- @return boolean of wether or not the current file is in a git repo +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.is_git_repo } +function astronvim.status.condition.is_git_repo(bufnr) + if type(bufnr) == "table" then bufnr = bufnr.bufnr end + return vim.b[bufnr or 0].gitsigns_head or vim.b[bufnr or 0].gitsigns_status_dict +end + +--- A condition function if there are any git changes +-- @param bufnr a buffer number to check the condition for, a table with bufnr property, or nil to get the current buffer +-- @return boolean of wether or not there are any git changes +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.git_changed } +function astronvim.status.condition.git_changed(bufnr) + if type(bufnr) == "table" then bufnr = bufnr.bufnr end + local git_status = vim.b[bufnr or 0].gitsigns_status_dict + return git_status and (git_status.added or 0) + (git_status.removed or 0) + (git_status.changed or 0) > 0 +end + +--- A condition function if the current buffer is modified +-- @param bufnr a buffer number to check the condition for, a table with bufnr property, or nil to get the current buffer +-- @return boolean of wether or not the current buffer is modified +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.file_modified } +function astronvim.status.condition.file_modified(bufnr) + if type(bufnr) == "table" then bufnr = bufnr.bufnr end + return vim.bo[bufnr or 0].modified +end + +--- A condition function if the current buffer is read only +-- @param bufnr a buffer number to check the condition for, a table with bufnr property, or nil to get the current buffer +-- @return boolean of wether or not the current buffer is read only or not modifiable +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.file_read_only } +function astronvim.status.condition.file_read_only(bufnr) + if type(bufnr) == "table" then bufnr = bufnr.bufnr end + local buffer = vim.bo[bufnr or 0] + return not buffer.modifiable or buffer.readonly +end + +--- A condition function if the current file has any diagnostics +-- @param bufnr a buffer number to check the condition for, a table with bufnr property, or nil to get the current buffer +-- @return boolean of wether or not the current file has any diagnostics +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.has_diagnostics } +function astronvim.status.condition.has_diagnostics(bufnr) + if type(bufnr) == "table" then bufnr = bufnr.bufnr end + return vim.g.status_diagnostics_enabled and #vim.diagnostic.get(bufnr or 0) > 0 +end + +--- A condition function if there is a defined filetype +-- @param bufnr a buffer number to check the condition for, a table with bufnr property, or nil to get the current buffer +-- @return boolean of wether or not there is a filetype +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.has_filetype } +function astronvim.status.condition.has_filetype(bufnr) + if type(bufnr) == "table" then bufnr = bufnr.bufnr end + return vim.fn.empty(vim.fn.expand "%:t") ~= 1 and vim.bo[bufnr or 0].filetype and vim.bo[bufnr or 0].filetype ~= "" +end + +--- A condition function if Aerial is available +-- @return boolean of wether or not aerial plugin is installed +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.aerial_available } +-- function astronvim.status.condition.aerial_available() return astronvim.is_available "aerial.nvim" end +function astronvim.status.condition.aerial_available() return package.loaded["aerial"] end + +--- A condition function if LSP is attached +-- @param bufnr a buffer number to check the condition for, a table with bufnr property, or nil to get the current buffer +-- @return boolean of wether or not LSP is attached +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.lsp_attached } +function astronvim.status.condition.lsp_attached(bufnr) + if type(bufnr) == "table" then bufnr = bufnr.bufnr end + return next(vim.lsp.get_active_clients { bufnr = bufnr or 0 }) ~= nil +end + +--- A condition function if treesitter is in use +-- @param bufnr a buffer number to check the condition for, a table with bufnr property, or nil to get the current buffer +-- @return boolean of wether or not treesitter is active +-- @usage local heirline_component = { provider = "Example Provider", condition = astronvim.status.condition.treesitter_available } +function astronvim.status.condition.treesitter_available(bufnr) + if not package.loaded["nvim-treesitter"] then return false end + if type(bufnr) == "table" then bufnr = bufnr.bufnr end + local parsers = require "nvim-treesitter.parsers" + return parsers.has_parser(parsers.get_buf_lang(bufnr or vim.api.nvim_get_current_buf())) +end + +--- A utility function to stylize a string with an icon from lspkind, separators, and left/right padding +-- @param str the string to stylize +-- @param opts options of `{ padding = { left = 0, right = 0 }, separator = { left = "|", right = "|" }, show_empty = false, icon = { kind = "NONE", padding = { left = 0, right = 0 } } }` +-- @return the stylized string +-- @usage local string = astronvim.status.utils.stylize("Hello", { padding = { left = 1, right = 1 }, icon = { kind = "String" } }) +function astronvim.status.utils.stylize(str, opts) + opts = astronvim.default_tbl(opts, { + padding = { left = 0, right = 0 }, + separator = { left = "", right = "" }, + show_empty = false, + icon = { kind = "NONE", padding = { left = 0, right = 0 } }, + }) + local icon = astronvim.pad_string(astronvim.get_icon(opts.icon.kind), opts.icon.padding) + return str + and (str ~= "" or opts.show_empty) + and opts.separator.left .. astronvim.pad_string(icon .. str, opts.padding) .. opts.separator.right + or "" +end + +--- A Heirline component for filling in the empty space of the bar +-- @param opts options for configuring the other fields of the heirline component +-- @return The heirline component table +-- @usage local heirline_component = astronvim.status.component.fill() +function astronvim.status.component.fill(opts) + return astronvim.default_tbl(opts, { provider = astronvim.status.provider.fill() }) +end + +--- A function to build a set of children components for an entire file information section +-- @param opts options for configuring file_icon, filename, filetype, file_modified, file_read_only, and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.file_info() +function astronvim.status.component.file_info(opts) + opts = astronvim.default_tbl(opts, { + file_icon = { + hl = astronvim.status.hl.file_icon "statusline", + padding = { left = 1, right = 1 }, + }, -- TODO: REWORK THIS + filename = {}, + file_modified = { padding = { left = 1 } }, + file_read_only = { padding = { left = 1 } }, + surround = { separator = "left", color = "file_info_bg", condition = astronvim.status.condition.has_filetype }, + hl = astronvim.status.hl.get_attributes "file_info", + }) + return astronvim.status.component.builder(astronvim.status.utils.setup_providers(opts, { + "file_icon", + "unique_path", + "filename", + "filetype", + "file_modified", + "file_read_only", + "close_button", + })) +end + +--- A function with different file_info defaults specifically for use in the tabline +-- @param opts options for configuring file_icon, filename, filetype, file_modified, file_read_only, and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.tabline_file_info() +function astronvim.status.component.tabline_file_info(opts) + return astronvim.status.component.file_info(astronvim.default_tbl(opts, { + file_icon = { + condition = function(self) return not self._show_picker end, + hl = astronvim.status.hl.file_icon "tabline", + }, + unique_path = { + hl = function(self) return astronvim.status.hl.get_attributes(self.tab_type .. "_path") end, + }, + close_button = { + hl = function(self) return astronvim.status.hl.get_attributes(self.tab_type .. "_close") end, + padding = { left = 1, right = 1 }, + on_click = { + callback = function(_, minwid) astronvim.close_buf(minwid) end, + minwid = function(self) return self.bufnr end, + name = "heirline_tabline_close_buffer_callback", + }, + }, + padding = { left = 1, right = 1 }, + hl = function(self) + local tab_type = self.tab_type + if self._show_picker and self.tab_type ~= "buffer_active" then tab_type = "buffer_visible" end + return astronvim.status.hl.get_attributes(tab_type) + end, + surround = false, + })) +end + +--- A function to build a set of children components for an entire navigation section +-- @param opts options for configuring ruler, percentage, scrollbar, and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.nav() +function astronvim.status.component.nav(opts) + opts = astronvim.default_tbl(opts, { + ruler = {}, + percentage = { padding = { left = 1 } }, + scrollbar = { padding = { left = 1 }, hl = { fg = "scrollbar" } }, + surround = { separator = "right", color = "nav_bg" }, + hl = astronvim.status.hl.get_attributes "nav", + update = { "CursorMoved", "BufEnter" }, + }) + return astronvim.status.component.builder( + astronvim.status.utils.setup_providers(opts, { "ruler", "percentage", "scrollbar" }) + ) +end + +--- A function to build a set of children components for a macro recording section +-- @param opts options for configuring macro recording and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.macro_recording() +-- TODO: deprecate on next major version release +function astronvim.status.component.macro_recording(opts) + opts = astronvim.default_tbl(opts, { + macro_recording = { icon = { kind = "MacroRecording", padding = { right = 1 } } }, + surround = { + separator = "center", + color = "macro_recording_bg", + condition = astronvim.status.condition.is_macro_recording, + }, + hl = astronvim.status.hl.get_attributes "macro_recording", + update = { "RecordingEnter", "RecordingLeave" }, + }) + return astronvim.status.component.builder(astronvim.status.utils.setup_providers(opts, { "macro_recording" })) +end + +--- A function to build a set of children components for information shown in the cmdline +-- @param opts options for configuring macro recording, search count, and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.cmd_info() +function astronvim.status.component.cmd_info(opts) + opts = astronvim.default_tbl(opts, { + macro_recording = { + icon = { kind = "MacroRecording", padding = { right = 1 } }, + condition = astronvim.status.condition.is_macro_recording, + update = { "RecordingEnter", "RecordingLeave" }, + }, + search_count = { + icon = { kind = "Search", padding = { right = 1 } }, + padding = { left = 1 }, + condition = astronvim.status.condition.is_hlsearch, + }, + surround = { + separator = "center", + color = "cmd_info_bg", + condition = function() + return astronvim.status.condition.is_hlsearch() or astronvim.status.condition.is_macro_recording() + end, + }, + condition = function() return vim.opt.cmdheight:get() == 0 end, + hl = astronvim.status.hl.get_attributes "cmd_info", + }) + return astronvim.status.component.builder( + astronvim.status.utils.setup_providers(opts, { "macro_recording", "search_count" }) + ) +end + +--- A function to build a set of children components for a mode section +-- @param opts options for configuring mode_text, paste, spell, and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.mode { mode_text = true } +function astronvim.status.component.mode(opts) + opts = astronvim.default_tbl(opts, { + mode_text = false, + paste = false, + spell = false, + surround = { separator = "left", color = astronvim.status.hl.mode_bg }, + hl = astronvim.status.hl.get_attributes "mode", + update = "ModeChanged", + }) + if not opts["mode_text"] then opts.str = { str = " " } end + return astronvim.status.component.builder( + astronvim.status.utils.setup_providers(opts, { "mode_text", "str", "paste", "spell" }) + ) +end + +--- A function to build a set of children components for an LSP breadcrumbs section +-- @param opts options for configuring breadcrumbs and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.breadcumbs() +function astronvim.status.component.breadcrumbs(opts) + opts = astronvim.default_tbl( + opts, + { padding = { left = 1 }, condition = astronvim.status.condition.aerial_available, update = "CursorMoved" } + ) + opts.init = astronvim.status.init.breadcrumbs(opts) + return opts +end + +--- A function to build a set of children components for a git branch section +-- @param opts options for configuring git branch and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.git_branch() +function astronvim.status.component.git_branch(opts) + opts = astronvim.default_tbl(opts, { + git_branch = { icon = { kind = "GitBranch", padding = { right = 1 } } }, + surround = { separator = "left", color = "git_branch_bg", condition = astronvim.status.condition.is_git_repo }, + hl = astronvim.status.hl.get_attributes "git_branch", + on_click = { + name = "heirline_branch", + callback = function() + if astronvim.is_available "telescope.nvim" then + vim.defer_fn(function() require("telescope.builtin").git_branches() end, 100) + end + end, + }, + update = { "User", pattern = "GitSignsUpdate" }, + init = astronvim.status.init.update_events { "BufEnter" }, + }) + return astronvim.status.component.builder(astronvim.status.utils.setup_providers(opts, { "git_branch" })) +end + +--- A function to build a set of children components for a git difference section +-- @param opts options for configuring git changes and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.git_diff() +function astronvim.status.component.git_diff(opts) + opts = astronvim.default_tbl(opts, { + added = { icon = { kind = "GitAdd", padding = { left = 1, right = 1 } } }, + changed = { icon = { kind = "GitChange", padding = { left = 1, right = 1 } } }, + removed = { icon = { kind = "GitDelete", padding = { left = 1, right = 1 } } }, + hl = astronvim.status.hl.get_attributes "git_diff", + on_click = { + name = "heirline_git", + callback = function() + if astronvim.is_available "telescope.nvim" then + vim.defer_fn(function() require("telescope.builtin").git_status() end, 100) + end + end, + }, + surround = { separator = "left", color = "git_diff_bg", condition = astronvim.status.condition.git_changed }, + update = { "User", pattern = "GitSignsUpdate" }, + init = astronvim.status.init.update_events { "BufEnter" }, + }) + return astronvim.status.component.builder( + astronvim.status.utils.setup_providers(opts, { "added", "changed", "removed" }, function(p_opts, provider) + local out = astronvim.status.utils.build_provider(p_opts, provider) + if out then + out.provider = "git_diff" + out.opts.type = provider + if out.hl == nil then out.hl = { fg = "git_" .. provider } end + end + return out + end) + ) +end + +--- A function to build a set of children components for a diagnostics section +-- @param opts options for configuring diagnostic providers and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.diagnostics() +function astronvim.status.component.diagnostics(opts) + opts = astronvim.default_tbl(opts, { + ERROR = { icon = { kind = "DiagnosticError", padding = { left = 1, right = 1 } } }, + WARN = { icon = { kind = "DiagnosticWarn", padding = { left = 1, right = 1 } } }, + INFO = { icon = { kind = "DiagnosticInfo", padding = { left = 1, right = 1 } } }, + HINT = { icon = { kind = "DiagnosticHint", padding = { left = 1, right = 1 } } }, + surround = { separator = "left", color = "diagnostics_bg", condition = astronvim.status.condition.has_diagnostics }, + hl = astronvim.status.hl.get_attributes "diagnostics", + on_click = { + name = "heirline_diagnostic", + callback = function() + if astronvim.is_available "telescope.nvim" then + vim.defer_fn(function() require("telescope.builtin").diagnostics() end, 100) + end + end, + }, + update = { "DiagnosticChanged", "BufEnter" }, + }) + return astronvim.status.component.builder( + astronvim.status.utils.setup_providers(opts, { "ERROR", "WARN", "INFO", "HINT" }, function(p_opts, provider) + local out = astronvim.status.utils.build_provider(p_opts, provider) + if out then + out.provider = "diagnostics" + out.opts.severity = provider + if out.hl == nil then out.hl = { fg = "diag_" .. provider } end + end + return out + end) + ) +end + +--- A function to build a set of children components for a Treesitter section +-- @param opts options for configuring diagnostic providers and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.treesitter() +function astronvim.status.component.treesitter(opts) + opts = astronvim.default_tbl(opts, { + str = { str = "TS", icon = { kind = "ActiveTS" } }, + surround = { + separator = "right", + color = "treesitter_bg", + condition = astronvim.status.condition.treesitter_available, + }, + hl = astronvim.status.hl.get_attributes "treesitter", + update = { "OptionSet", pattern = "syntax" }, + init = astronvim.status.init.update_events { "BufEnter" }, + }) + return astronvim.status.component.builder(astronvim.status.utils.setup_providers(opts, { "str" })) +end + +--- A function to build a set of children components for an LSP section +-- @param opts options for configuring lsp progress and client_name providers and the overall padding +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.component.lsp() +function astronvim.status.component.lsp(opts) + opts = astronvim.default_tbl(opts, { + lsp_progress = { + str = "", + padding = { right = 1 }, + update = { "User", pattern = { "LspProgressUpdate", "LspRequest" } }, + }, + lsp_client_names = { + str = "LSP", + update = { "LspAttach", "LspDetach", "BufEnter" }, + icon = { kind = "ActiveLSP", padding = { right = 2 } }, + }, + hl = astronvim.status.hl.get_attributes "lsp", + surround = { separator = "right", color = "lsp_bg", condition = astronvim.status.condition.lsp_attached }, + on_click = { + name = "heirline_lsp", + callback = function() + vim.defer_fn(function() vim.cmd.LspInfo() end, 100) + end, + }, + }) + return astronvim.status.component.builder( + astronvim.status.utils.setup_providers( + opts, + { "lsp_progress", "lsp_client_names" }, + function(p_opts, provider, i) + return p_opts + and { + flexible = i, + astronvim.status.utils.build_provider(p_opts, astronvim.status.provider[provider](p_opts)), + astronvim.status.utils.build_provider(p_opts, astronvim.status.provider.str(p_opts)), + } + or false + end + ) + ) +end + +--- A general function to build a section of astronvim status providers with highlights, conditions, and section surrounding +-- @param opts a list of components to build into a section +-- @return The Heirline component table +-- @usage local heirline_component = astronvim.status.components.builder({ { provider = "file_icon", opts = { padding = { right = 1 } } }, { provider = "filename" } }) +function astronvim.status.component.builder(opts) + opts = astronvim.default_tbl(opts, { padding = { left = 0, right = 0 } }) + local children = {} + if opts.padding.left > 0 then -- add left padding + table.insert(children, { provider = astronvim.pad_string(" ", { left = opts.padding.left - 1 }) }) + end + for key, entry in pairs(opts) do + if + type(key) == "number" + and type(entry) == "table" + and astronvim.status.provider[entry.provider] + and (entry.opts == nil or type(entry.opts) == "table") + then + entry.provider = astronvim.status.provider[entry.provider](entry.opts) + end + children[key] = entry + end + if opts.padding.right > 0 then -- add right padding + table.insert(children, { provider = astronvim.pad_string(" ", { right = opts.padding.right - 1 }) }) + end + return opts.surround + and astronvim.status.utils.surround( + opts.surround.separator, + opts.surround.color, + children, + opts.surround.condition + ) + or children +end + +--- Convert a component parameter table to a table that can be used with the component builder +-- @param opts a table of provider options +-- @param provider a provider in `astronvim.status.providers` +-- @return the provider table that can be used in `astronvim.status.component.builder` +function astronvim.status.utils.build_provider(opts, provider, _) + return opts + and { + provider = provider, + opts = opts, + condition = opts.condition, + on_click = opts.on_click, + update = opts.update, + hl = opts.hl, + } + or false +end + +--- Convert key/value table of options to an array of providers for the component builder +-- @param opts the table of options for the components +-- @param providers an ordered list like array of providers that are configured in the options table +-- @param setup a function that takes provider options table, provider name, provider index and returns the setup provider table, optional, default is `astronvim.status.utils.build_provider` +-- @return the fully setup options table with the appropriately ordered providers +function astronvim.status.utils.setup_providers(opts, providers, setup) + setup = setup or astronvim.status.utils.build_provider + for i, provider in ipairs(providers) do + opts[i] = setup(opts[provider], provider, i) + end + return opts +end + +--- A utility function to get the width of the bar +-- @param is_winbar boolean true if you want the width of the winbar, false if you want the statusline width +-- @return the width of the specified bar +function astronvim.status.utils.width(is_winbar) + return vim.o.laststatus == 3 and not is_winbar and vim.o.columns or vim.api.nvim_win_get_width(0) +end + +--- Surround component with separator and color adjustment +-- @param separator the separator index to use in `astronvim.status.env.separators` +-- @param color the color to use as the separator foreground/component background +-- @param component the component to surround +-- @param condition the condition for displaying the surrounded component +-- @return the new surrounded component +function astronvim.status.utils.surround(separator, color, component, condition) + local function surround_color(self) + local colors = type(color) == "function" and color(self) or color + return type(colors) == "string" and { main = colors } or colors + end + + separator = type(separator) == "string" and astronvim.status.env.separators[separator] or separator + local surrounded = { condition = condition } + if separator[1] ~= "" then + table.insert(surrounded, { + provider = separator[1], + hl = function(self) + local s_color = surround_color(self) + if s_color then return { fg = s_color.main, bg = s_color.left } end + end, + }) + end + table.insert(surrounded, { + hl = function(self) + local s_color = surround_color(self) + if s_color then return { bg = s_color.main } end + end, + astronvim.default_tbl({}, component), + }) + if separator[2] ~= "" then + table.insert(surrounded, { + provider = separator[2], + hl = function(self) + local s_color = surround_color(self) + if s_color then return { fg = s_color.main, bg = s_color.right } end + end, + }) + end + return surrounded +end + +--- Check if a buffer is valid +-- @param bufnr the buffer to check +-- @return true if the buffer is valid or false +function astronvim.status.utils.is_valid_buffer(bufnr) -- TODO v3: remove this function + if not bufnr or bufnr < 1 then return false end + return vim.bo[bufnr].buflisted and vim.api.nvim_buf_is_valid(bufnr) +end + +--- Get all valid buffers +-- @return array-like table of valid buffer numbers +function astronvim.status.utils.get_valid_buffers() -- TODO v3: remove this function + return vim.tbl_filter(astronvim.status.utils.is_valid_buffer, vim.api.nvim_list_bufs()) +end + +--- Encode a position to a single value that can be decoded later +-- @param line line number of position +-- @param col column number of position +-- @param winnr a window number +-- @return the encoded position +function astronvim.status.utils.encode_pos(line, col, winnr) + return bit.bor(bit.lshift(line, 16), bit.lshift(col, 6), winnr) +end + +--- Decode a previously encoded position to it's sub parts +-- @param c the encoded position +-- @return line number, column number, window id +function astronvim.status.utils.decode_pos(c) + return bit.rshift(c, 16), bit.band(bit.rshift(c, 6), 1023), bit.band(c, 63) +end + +return astronvim.status diff --git a/lua/core/utils/ui.lua b/lua/core/utils/ui.lua new file mode 100644 index 0000000..256b358 --- /dev/null +++ b/lua/core/utils/ui.lua @@ -0,0 +1,188 @@ +--- ### AstroNvim UI Options +-- +-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim.ui` +-- +-- This module can also be manually loaded with `local updater = require("core.utils").ui` +-- +-- @module core.utils.ui +-- @see core.utils +-- @copyright 2022 +-- @license GNU General Public License v3.0 + +astronvim.ui = {} + +local function bool2str(bool) return bool and "on" or "off" end + +local function ui_notify(str) + if vim.g.ui_notifications_enabled then astronvim.notify(str) end +end + +--- Toggle notifications for UI toggles +function astronvim.ui.toggle_ui_notifications() + vim.g.ui_notifications_enabled = not vim.g.ui_notifications_enabled + ui_notify(string.format("ui notifications %s", bool2str(vim.g.ui_notifications_enabled))) +end + +--- Toggle autopairs +function astronvim.ui.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 + ui_notify(string.format("autopairs %s", bool2str(not autopairs.state.disabled))) + else + ui_notify "autopairs not available" + end +end + +--- Toggle diagnostics +function astronvim.ui.toggle_diagnostics() + local status = "on" + if vim.g.status_diagnostics_enabled then + if vim.g.diagnostics_enabled then + vim.g.diagnostics_enabled = false + status = "virtual text off" + else + vim.g.status_diagnostics_enabled = false + status = "fully off" + end + else + vim.g.diagnostics_enabled = true + vim.g.status_diagnostics_enabled = true + end + + vim.diagnostic.config(astronvim.lsp.diagnostics[bool2str(vim.g.diagnostics_enabled)]) + ui_notify(string.format("diagnostics %s", status)) +end + +--- Toggle background="dark"|"light" +function astronvim.ui.toggle_background() + vim.go.background = vim.go.background == "light" and "dark" or "light" + ui_notify(string.format("background=%s", vim.go.background)) +end + +--- Toggle cmp entrirely +function astronvim.ui.toggle_cmp() + vim.g.cmp_enabled = not vim.g.cmp_enabled + local ok, _ = pcall(require, "cmp") + ui_notify(ok and string.format("completion %s", bool2str(vim.g.cmp_enabled)) or "completion not available") +end + +--- Toggle auto format +function astronvim.ui.toggle_autoformat() + vim.g.autoformat_enabled = not vim.g.autoformat_enabled + ui_notify(string.format("Autoformatting %s", bool2str(vim.g.autoformat_enabled))) +end + +--- Toggle showtabline=2|0 +function astronvim.ui.toggle_tabline() + vim.opt.showtabline = vim.opt.showtabline:get() == 0 and 2 or 0 + ui_notify(string.format("tabline %s", bool2str(vim.opt.showtabline:get() == 2))) +end + +--- Toggle conceal=2|0 +function astronvim.ui.toggle_conceal() + vim.opt.conceallevel = vim.opt.conceallevel:get() == 0 and 2 or 0 + ui_notify(string.format("conceal %s", bool2str(vim.opt.conceallevel:get() == 2))) +end + +--- Toggle laststatus=3|2|0 +function astronvim.ui.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 + ui_notify(string.format("statusline %s", status)) +end + +--- Toggle signcolumn="auto"|"no" +function astronvim.ui.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 + ui_notify(string.format("signcolumn=%s", vim.wo.signcolumn)) +end + +--- Set the indent and tab related numbers +function astronvim.ui.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 + ui_notify(string.format("indent=%d %s", indent, vim.bo.expandtab and "expandtab" or "noexpandtab")) + end +end + +--- Change the number display modes +function astronvim.ui.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 + ui_notify(string.format("number %s, relativenumber %s", bool2str(vim.wo.number), bool2str(vim.wo.relativenumber))) +end + +--- Toggle spell +function astronvim.ui.toggle_spell() + vim.wo.spell = not vim.wo.spell -- local to window + ui_notify(string.format("spell %s", bool2str(vim.wo.spell))) +end + +--- Toggle paste +function astronvim.ui.toggle_paste() + vim.opt.paste = not vim.opt.paste:get() -- local to window + ui_notify(string.format("paste %s", bool2str(vim.opt.paste:get()))) +end + +--- Toggle wrap +function astronvim.ui.toggle_wrap() + vim.wo.wrap = not vim.wo.wrap -- local to window + ui_notify(string.format("wrap %s", bool2str(vim.wo.wrap))) +end + +--- Toggle syntax highlighting and treesitter +function astronvim.ui.toggle_syntax() + local ts_avail, parsers = pcall(require, "nvim-treesitter.parsers") + if vim.g.syntax_on then -- global var for on//off + if ts_avail and parsers.has_parser() then vim.cmd.TSBufDisable "highlight" end + vim.cmd.syntax "off" -- set vim.g.syntax_on = false + else + if ts_avail and parsers.has_parser() then vim.cmd.TSBufEnable "highlight" end + vim.cmd.syntax "on" -- set vim.g.syntax_on = true + end + ui_notify(string.format("syntax %s", bool2str(vim.g.syntax_on))) +end + +--- Toggle URL/URI syntax highlighting rules +function astronvim.ui.toggle_url_match() + vim.g.highlighturl_enabled = not vim.g.highlighturl_enabled + astronvim.set_url_match() +end diff --git a/lua/core/utils/updater.lua b/lua/core/utils/updater.lua new file mode 100644 index 0000000..ce85be6 --- /dev/null +++ b/lua/core/utils/updater.lua @@ -0,0 +1,296 @@ +--- ### AstroNvim Updater +-- +-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim.updater` +-- +-- This module can also be manually loaded with `local updater = require("core.utils").updater` +-- +-- @module core.utils.updater +-- @see core.utils +-- @copyright 2022 +-- @license GNU General Public License v3.0 + +local fn = vim.fn +local git = require "core.utils.git" +--- Updater settings overridden with any user provided configuration +local options = astronvim.user_plugin_opts("updater", { + remote = "origin", + channel = "stable", + show_changelog = true, + auto_reload = true, + auto_quit = true, +}) + +-- set the install channel +if options.branch and options.branch ~= "main" then options.channel = "nightly" end +if astronvim.install.is_stable ~= nil then options.channel = astronvim.install.is_stable and "stable" or "nightly" end + +astronvim.updater = { options = options } +-- if the channel is stable or the user has chosen to pin the system plugins +if options.pin_plugins == nil and options.channel == "stable" or options.pin_plugins then + -- load the current packer snapshot from the installation home location + local loaded, snapshot = pcall(fn.readfile, astronvim.install.home .. "/packer_snapshot") + if loaded then + -- decode the snapshot JSON and save it to a variable + loaded, snapshot = pcall(fn.json_decode, snapshot) + astronvim.updater.snapshot = type(snapshot) == "table" and snapshot or nil + end + -- if there is an error loading the snapshot, print an error + if not loaded then vim.api.nvim_err_writeln "Error loading packer snapshot" end +end + +--- Get the current AstroNvim version +-- @param quiet boolean to quietly execute or send a notification +-- @return the current AstroNvim version string +function astronvim.updater.version(quiet) + local version = astronvim.install.version or git.current_version(false) + if version and not quiet then astronvim.notify("Version: " .. version) end + return version +end + +--- Get the full AstroNvim changelog +-- @param quiet boolean to quietly execute or display the changelog +-- @return the current AstroNvim changelog table of commit messages +function astronvim.updater.changelog(quiet) + local summary = {} + vim.list_extend(summary, git.pretty_changelog(git.get_commit_range())) + if not quiet then astronvim.echo(summary) end + return summary +end + +--- Attempt an update of AstroNvim +-- @param target the target if checking out a specific tag or commit or nil if just pulling +local function attempt_update(target) + -- if updating to a new stable version or a specific commit checkout the provided target + if options.channel == "stable" or options.commit then + return git.checkout(target, false) + -- if no target, pull the latest + else + return git.pull(false) + end +end + +--- Cancelled update message +local cancelled_message = { { "Update cancelled", "WarningMsg" } } + +--- Reload the AstroNvim configuration live (Experimental) +-- @param quiet boolean to quietly execute or send a notification +function astronvim.updater.reload(quiet) + -- stop LSP if it is running + if vim.fn.exists ":LspStop" ~= 0 then vim.cmd.LspStop() end + local reload_module = require("plenary.reload").reload_module + -- unload AstroNvim configuration files + reload_module "user" + reload_module "configs" + reload_module "default_theme" + reload_module "core" + -- manual unload some plugins that need it if they exist + reload_module "cmp" + reload_module "which-key" + -- source the AstroNvim configuration + local reloaded, _ = pcall(dofile, vim.fn.expand "$MYVIMRC") + -- if successful reload and not quiet, display a notification + if reloaded and not quiet then astronvim.notify "Reloaded AstroNvim" end +end + +--- Sync Packer and then update Mason +function astronvim.updater.update_packages() + vim.api.nvim_create_autocmd("User", { + once = true, + desc = "Update Mason with Packer", + group = vim.api.nvim_create_augroup("astro_sync", { clear = true }), + pattern = "PackerComplete", + callback = function() + if astronvim.is_available "mason.nvim" then + vim.api.nvim_create_autocmd("User", { + pattern = "AstroMasonUpdateComplete", + once = true, + callback = function() astronvim.event "UpdatePackagesComplete" end, + }) + astronvim.mason.update_all() + else + astronvim.event "UpdatePackagesComplete" + end + end, + }) + vim.cmd.PackerSync() +end + +--- AstroNvim's updater function +function astronvim.updater.update() + -- if the git command is not available, then throw an error + if not git.available() then + astronvim.notify( + "git command is not available, please verify it is accessible in a command line. This may be an issue with your PATH", + "error" + ) + return + end + + -- if installed with an external package manager, disable the internal updater + if not git.is_repo() then + astronvim.notify("Updater not available for non-git installations", "error") + return + end + -- set up any remotes defined by the user if they do not exist + for remote, entry in pairs(options.remotes and options.remotes or {}) do + local url = git.parse_remote_url(entry) + local current_url = git.remote_url(remote, false) + local check_needed = false + if not current_url then + git.remote_add(remote, url) + check_needed = true + elseif + current_url ~= url + and astronvim.confirm_prompt { + { "Remote " }, + { remote, "Title" }, + { " is currently set to " }, + { current_url, "WarningMsg" }, + { "\nWould you like us to set it to " }, + { url, "String" }, + { "?" }, + } + then + git.remote_update(remote, url) + check_needed = true + end + if check_needed and git.remote_url(remote, false) ~= url then + vim.api.nvim_err_writeln("Error setting up remote " .. remote .. " to " .. url) + return + end + end + local is_stable = options.channel == "stable" + if is_stable then + options.branch = "main" + elseif not options.branch then + options.branch = "nightly" + end + -- fetch the latest remote + if not git.fetch(options.remote) then + vim.api.nvim_err_writeln("Error fetching remote: " .. options.remote) + return + end + -- switch to the necessary branch only if not on the stable channel + if not is_stable then + local local_branch = (options.remote == "origin" and "" or (options.remote .. "_")) .. options.branch + if git.current_branch() ~= local_branch then + astronvim.echo { + { "Switching to branch: " }, + { options.remote .. "/" .. options.branch .. "\n\n", "String" }, + } + if not git.checkout(local_branch, false) then + git.checkout("-b " .. local_branch .. " " .. options.remote .. "/" .. options.branch, false) + end + end + -- check if the branch was switched to successfully + if git.current_branch() ~= local_branch then + vim.api.nvim_err_writeln("Error checking out branch: " .. options.remote .. "/" .. options.branch) + return + end + end + local source = git.local_head() -- calculate current commit + local target -- calculate target commit + if is_stable then -- if stable get tag commit + local version_search = options.version or "latest" + options.version = git.latest_version(git.get_versions(version_search)) + if not options.version then -- continue only if stable version is found + vim.api.nvim_err_writeln("Error finding version: " .. version_search) + return + end + target = git.tag_commit(options.version) + elseif options.commit then -- if commit specified use it + target = git.branch_contains(options.remote, options.branch, options.commit) and options.commit or nil + else -- get most recent commit + target = git.remote_head(options.remote, options.branch) + end + if not source or not target then -- continue if current and target commits were found + vim.api.nvim_err_writeln "Error checking for updates" + return + elseif source == target then + astronvim.echo { { "No updates available", "String" } } + return + elseif -- prompt user if they want to accept update + not options.skip_prompts + and not astronvim.confirm_prompt { + { "Update available to ", "Title" }, + { is_stable and options.version or target, "String" }, + { "\nUpdating requires a restart, continue?" }, + } + then + astronvim.echo(cancelled_message) + return + else -- perform update + -- calculate and print the changelog + local changelog = git.get_commit_range(source, target) + local breaking = git.breaking_changes(changelog) + local breaking_prompt = { { "Update contains the following breaking changes:\n", "WarningMsg" } } + vim.list_extend(breaking_prompt, git.pretty_changelog(breaking)) + vim.list_extend(breaking_prompt, { { "\nWould you like to continue?" } }) + if #breaking > 0 and not options.skip_prompts and not astronvim.confirm_prompt(breaking_prompt) then + astronvim.echo(cancelled_message) + return + end + -- attempt an update + local updated = attempt_update(target) + -- check for local file conflicts and prompt user to continue or abort + if + not updated + and not options.skip_prompts + and not astronvim.confirm_prompt { + { "Unable to pull due to local modifications to base files.\n", "ErrorMsg" }, + { "Reset local files and continue?" }, + } + then + astronvim.echo(cancelled_message) + return + -- if continued and there were errors reset the base config and attempt another update + elseif not updated then + git.hard_reset(source) + updated = attempt_update(target) + end + -- if update was unsuccessful throw an error + if not updated then + vim.api.nvim_err_writeln "Error ocurred performing update" + return + end + -- print a summary of the update with the changelog + local summary = { + { "AstroNvim updated successfully to ", "Title" }, + { git.current_version(), "String" }, + { "!\n", "Title" }, + { + options.auto_reload and "AstroNvim will now sync packer and quit.\n\n" + or "Please restart and run :PackerSync.\n\n", + "WarningMsg", + }, + } + if options.show_changelog and #changelog > 0 then + vim.list_extend(summary, { { "Changelog:\n", "Title" } }) + vim.list_extend(summary, git.pretty_changelog(changelog)) + end + astronvim.echo(summary) + + -- if the user wants to auto quit, create an autocommand to quit AstroNvim on the update completing + if options.auto_quit then + vim.api.nvim_create_autocmd("User", { pattern = "AstroUpdateComplete", command = "quitall" }) + end + + -- if the user wants to reload and sync packer + if options.auto_reload then + -- perform a reload + vim.opt.modifiable = true + astronvim.updater.reload(true) -- run quiet to not show notification on reload + vim.api.nvim_create_autocmd("User", { + once = true, + pattern = "AstroUpdatePackagesComplete", + callback = function() astronvim.event "UpdateComplete" end, + }) + require "core.plugins" + astronvim.updater.update_packages() + -- if packer isn't available send successful update event + else + -- send user event of successful update + astronvim.event "UpdateComplete" + end + end +end diff --git a/lua/default_theme/base.lua b/lua/default_theme/base.lua new file mode 100644 index 0000000..ff0690a --- /dev/null +++ b/lua/default_theme/base.lua @@ -0,0 +1,86 @@ +local base = { + Normal = { fg = C.fg, bg = C.bg }, + NormalNC = { fg = C.fg, bg = C.black }, + Comment = { fg = C.grey_2, bg = C.none }, + Constant = { fg = C.yellow, bg = C.none }, + String = { fg = C.green, bg = C.none }, + Character = { fg = C.green, bg = C.none }, + Number = { fg = C.orange, bg = C.none }, + Boolean = { fg = C.blue, bg = C.none }, + Float = { fg = C.yellow, bg = C.none }, + Identifier = { fg = C.blue, bg = C.none }, + Function = { fg = C.yellow, bg = C.none }, + Statement = { fg = C.purple, bg = C.none }, + Conditional = { fg = C.purple_1, bg = C.none }, + Repeat = { fg = C.purple, bg = C.none }, + Label = { fg = C.blue, bg = C.none }, + Operator = { fg = C.purple, bg = C.none }, + Keyword = { fg = C.purple, bg = C.none }, + Exception = { fg = C.purple, bg = C.none }, + Preproc = { fg = C.yellow, bg = C.none }, + Include = { fg = C.purple, bg = C.none }, + Define = { fg = C.purple, bg = C.none }, + Title = { fg = C.cyan, bg = C.none }, + Macro = { fg = C.purple, bg = C.none }, + PreCondit = { fg = C.blue, bg = C.none }, + Type = { fg = C.blue, bg = C.none }, + StorageClass = { fg = C.blue, bg = C.none }, + Structure = { fg = C.yellow, bg = C.none }, + Typedef = { fg = C.yellow, bg = C.none }, + Special = { fg = C.blue, bg = C.none }, + SpecialComment = { fg = C.grey, bg = C.none }, + Error = { fg = C.red, bg = C.none }, + Todo = { fg = C.purple, bg = C.none }, + Underlined = { fg = C.cyan, bg = C.none }, + Cursor = { fg = C.none, bg = C.none }, + ColorColumn = { fg = C.none, bg = C.grey_4 }, + CursorLineNr = { fg = C.fg, bg = C.none }, + Conceal = { fg = C.grey, bg = C.none }, + CursorColumn = { fg = C.none, bg = C.grey_4 }, + CursorLine = { fg = C.none, bg = C.grey_8 }, + Directory = { fg = C.blue, bg = C.none }, + DiffAdd = { fg = C.grey_3, bg = C.green }, + DiffChange = { fg = C.yellow, bg = C.none }, + DiffDelete = { fg = C.grey_3, bg = C.red }, + DiffText = { fg = C.grey_3, bg = C.yellow }, + ErrorMsg = { fg = C.red, bg = C.none }, + WinSeparator = { fg = C.grey_4, bg = C.none }, + Folded = { fg = C.grey, bg = C.none }, + FoldColumn = { fg = C.none, bg = C.none }, + IncSearch = { fg = C.yellow, bg = C.grey }, + CurSearch = { link = "IncSearch" }, + LineNr = { fg = C.grey_1, bg = C.none }, + NonText = { fg = C.grey_1, bg = C.none }, + Pmenu = { fg = C.fg, bg = C.bg }, + PmenuSel = { fg = C.none, bg = C.grey_4 }, + PmenuSbar = { fg = C.none, bg = C.grey_3 }, + PmenuThumb = { fg = C.none, bg = C.fg }, + Question = { fg = C.purple, bg = C.none }, + QuickFixLine = { fg = C.grey_3, bg = C.yellow }, + Search = { fg = C.grey_3, bg = C.yellow }, + SignColumn = { fg = C.none, bg = C.none }, + SpecialKey = { fg = C.grey_1, bg = C.none }, + SpellBad = { undercurl = true }, + SpellCap = { undercurl = true }, + SpellLocal = { undercurl = true }, + SpellRare = { undercurl = true }, + StatusLine = { fg = C.fg, bg = C.grey_4 }, + StatusLineNC = { fg = C.grey, bg = C.none }, + StatusLineTerm = { fg = C.fg, bg = C.grey_4 }, + StatusLineTermNC = { fg = C.grey_4, bg = C.none }, + WinBar = { fg = C.grey_2, bg = C.bg }, + WinBarNC = { fg = C.grey, bg = C.black }, + TabLine = { fg = C.grey, bg = C.none }, + TabLineSel = { fg = C.fg, bg = C.none }, + TabLineFill = { fg = C.none, bg = C.grey_3 }, + Terminal = { fg = C.fg, bg = C.grey_3 }, + Visual = { fg = C.none, bg = C.grey_5 }, + VisualNOS = { fg = C.grey_5, bg = C.none }, + WarningMsg = { fg = C.yellow, bg = C.none }, + WildMenu = { fg = C.grey_3, bg = C.blue }, + EndOfBuffer = { fg = C.bg, bg = C.none }, + FloatBorder = { fg = C.grey_6, bg = C.bg }, + MatchParen = { fg = C.none, bg = C.grey_5 }, +} + +return base diff --git a/lua/default_theme/colors.lua b/lua/default_theme/colors.lua new file mode 100644 index 0000000..1fe8d76 --- /dev/null +++ b/lua/default_theme/colors.lua @@ -0,0 +1,82 @@ +local colors = { + none = "NONE", + fg = "#abb2bf", + bg = "#1e222a", + bg_1 = "#303742", + black = "#181a1f", + black_1 = "#1f1f25", + green = "#98c379", + green_1 = "#89b06d", + green_2 = "#95be76", + white = "#dedede", + white_1 = "#afb2bb", + white_2 = "#c9c9c9", + blue = "#61afef", + blue_1 = "#40d9ff", + blue_2 = "#1b1f27", + blue_3 = "#8094B4", + blue_4 = "#90c7f3", + orange = "#d19a66", + orange_1 = "#ff9640", + orange_2 = "#ff8800", + yellow = "#e5c07b", + yellow_1 = "#ebae34", + yellow_2 = "#d1b071", + red = "#e06c75", + red_1 = "#ec5f67", + red_2 = "#ffbba6", + red_3 = "#cc626a", + red_4 = "#d47d85", + red_5 = "#e9989e", + grey = "#5c6370", + grey_1 = "#4b5263", + grey_2 = "#777d86", + grey_3 = "#282c34", + grey_4 = "#2c323c", + grey_5 = "#3e4452", + grey_6 = "#3b4048", + grey_7 = "#5c5c5c", + grey_8 = "#252931", + grey_9 = "#787e87", + grey_10 = "#D3D3D3", + gold = "#ffcc00", + cyan = "#56b6c2", + cyan_1 = "#88cbd4", + purple = "#c678dd", + purple_1 = "#a9a1e1", + purple_2 = "#c2bdea", + + -- icon colors + c = "#519aba", + css = "#61afef", + deb = "#a1b7ee", + docker = "#384d54", + html = "#de8c92", + jpeg = "#c882e7", + jpg = "#c882e7", + js = "#ebcb8b", + jsx = "#519ab8", + kt = "#7bc99c", + lock = "#c4c720", + lua = "#51a0cf", + mp3 = "#d39ede", + mp4 = "#9ea3de", + out = "#abb2bf", + png = "#c882e7", + py = "#a3b8ef", + rb = "#ff75a0", + robots = "#abb2bf", + rpm = "#fca2aa", + rs = "#dea584", + toml = "#39bf39", + ts = "#519aba", + ttf = "#abb2bf", + vue = "#7bc99c", + woff = "#abb2bf", + woff2 = "#abb2bf", + zip = "#f9d71c", + md = "#519aba", + pkg = "#d39ede", +} + +return astronvim.user_plugin_opts("default_theme.colors", colors) diff --git a/lua/default_theme/init.lua b/lua/default_theme/init.lua new file mode 100644 index 0000000..421d913 --- /dev/null +++ b/lua/default_theme/init.lua @@ -0,0 +1,68 @@ +vim.cmd.highlight "clear" +if vim.fn.exists "syntax_on" then vim.cmd.syntax "reset" end +vim.o.background = "dark" +vim.o.termguicolors = true +vim.g.colors_name = "default_theme" + +local user_plugin_opts = astronvim.user_plugin_opts + +C = require "default_theme.colors" + +local highlights = {} + +for _, module in ipairs { "base", "lsp" } do + highlights = vim.tbl_deep_extend("force", highlights, require("default_theme." .. module)) +end + +for plugin, enabled in + pairs(user_plugin_opts("default_theme.plugins", { + aerial = true, + beacon = false, + bufferline = true, -- TODO v3: make this false + cmp = true, + dapui = true, + dashboard = true, + gitsigns = true, + highlighturl = true, + hop = false, + indent_blankline = true, + lightspeed = false, + ["neo-tree"] = true, + notify = true, + ["nvim-tree"] = false, + ["nvim-web-devicons"] = true, + rainbow = true, + symbols_outline = false, + telescope = true, + treesitter = true, + vimwiki = false, + ["which-key"] = true, + })) +do + if enabled then highlights = vim.tbl_deep_extend("force", highlights, require("default_theme.plugins." .. plugin)) end +end + +for group, spec in pairs(user_plugin_opts("default_theme.highlights", highlights)) do + vim.api.nvim_set_hl(0, group, spec) +end + +astronvim.vim_opts { + g = { + terminal_color_0 = C.terminal_color_0 or C.bg, + terminal_color_1 = C.terminal_color_1 or C.red, + terminal_color_2 = C.terminal_color_2 or C.green_1, + terminal_color_3 = C.terminal_color_3 or C.yellow_1, + terminal_color_4 = C.terminal_color_4 or C.blue, + terminal_color_5 = C.terminal_color_5 or C.purple_1, + terminal_color_6 = C.terminal_color_6 or C.cyan, + terminal_color_7 = C.terminal_color_7 or C.white, + terminal_color_8 = C.terminal_color_8 or C.white_1, + terminal_color_9 = C.terminal_color_9 or C.red_5, + terminal_color_10 = C.terminal_color_10 or C.green, + terminal_color_11 = C.terminal_color_11 or C.yellow, + terminal_color_12 = C.terminal_color_12 or C.blue_4, + terminal_color_13 = C.terminal_color_13 or C.purple_2, + terminal_color_14 = C.terminal_color_14 or C.cyan_1, + terminal_color_15 = C.terminal_color_15 or C.fg, + }, +} diff --git a/lua/default_theme/lsp.lua b/lua/default_theme/lsp.lua new file mode 100644 index 0000000..2bb6573 --- /dev/null +++ b/lua/default_theme/lsp.lua @@ -0,0 +1,26 @@ +local lsp = { + DiagnosticError = { fg = C.red_1 }, + DiagnosticHint = { fg = C.yellow_1 }, + DiagnosticInfo = { fg = C.white_2 }, + DiagnosticWarn = { fg = C.orange_1 }, + DiagnosticInformation = { fg = C.yellow, bold = true }, + DiagnosticTruncateLine = { fg = C.white_1, bold = true }, + DiagnosticUnderlineError = { sp = C.red_2, undercurl = true }, + DiagnosticUnderlineHint = { sp = C.red_2, undercurl = true }, + DiagnosticUnderlineInfo = { sp = C.red_2, undercurl = true }, + DiagnosticUnderlineWarn = { sp = C.red_2, undercurl = true }, + LspCodeLens = { fg = C.grey_2 }, + LspCodeLensSeparator = { fg = C.grey }, + LspDiagnosticsFloatingError = { fg = C.red_1 }, + LspDiagnosticsFloatingHint = { fg = C.yellow_1 }, + LspDiagnosticsFloatingInfor = { fg = C.white_2 }, + LspDiagnosticsFloatingWarn = { fg = C.orange_1 }, + LspFloatWinBorder = { fg = C.white_1 }, + LspFloatWinNormal = { fg = C.fg, bg = C.black_1 }, + LspReferenceRead = { fg = C.none, bg = C.grey_5 }, + LspReferenceText = { fg = C.none, bg = C.grey_5 }, + LspReferenceWrite = { fg = C.none, bg = C.grey_5 }, + ProviderTruncateLine = { fg = C.white_1 }, +} + +return lsp diff --git a/lua/default_theme/plugins/aerial.lua b/lua/default_theme/plugins/aerial.lua new file mode 100644 index 0000000..2e295ff --- /dev/null +++ b/lua/default_theme/plugins/aerial.lua @@ -0,0 +1,31 @@ +return { + AerialArrayIcon = { link = "@constant" }, + AerialBooleanIcon = { link = "@boolean" }, + AerialClassIcon = { link = "@type" }, + AerialConstantIcon = { link = "@constant" }, + AerialConstructorIcon = { link = "@constructor" }, + AerialEnumIcon = { link = "@type" }, + AerialEnumMemberIcon = { link = "@field" }, + AerialEventIcon = { link = "@type" }, + AerialFieldIcon = { link = "@field" }, + AerialFileIcon = { link = "@text.uri" }, + AerialFunctionIcon = { link = "@function" }, + AerialGuide = { fg = C.grey_2 }, + AerialInterfaceIcon = { link = "@type" }, + AerialKeyIcon = { link = "@type" }, + AerialLine = { fg = C.yellow, bg = C.none }, + AerialMethodIcon = { link = "@method" }, + AerialModuleIcon = { link = "@namespace" }, + AerialNamespaceIcon = { link = "@namespace" }, + AerialNullIcon = { link = "@type" }, + AerialNumberIcon = { link = "@number" }, + AerialObjectIcon = { link = "@type" }, + AerialOperatorIcon = { link = "@operator" }, + AerialPackageIcon = { link = "@namespace" }, + AerialPropertyIcon = { link = "@property" }, + AerialStringIcon = { link = "@string" }, + AerialStructIcon = { link = "@type" }, + AerialTypeIcon = { link = "@type" }, + AerialTypeParameterIcon = { link = "@parameter" }, + AerialVariableIcon = { link = "@variable" }, +} diff --git a/lua/default_theme/plugins/beacon.lua b/lua/default_theme/plugins/beacon.lua new file mode 100644 index 0000000..43b34b8 --- /dev/null +++ b/lua/default_theme/plugins/beacon.lua @@ -0,0 +1 @@ +return { Beacon = { bg = C.blue } } diff --git a/lua/default_theme/plugins/bufferline.lua b/lua/default_theme/plugins/bufferline.lua new file mode 100644 index 0000000..324a475 --- /dev/null +++ b/lua/default_theme/plugins/bufferline.lua @@ -0,0 +1,14 @@ +return { + BufferLineBufferVisible = { fg = C.fg, bg = C.bg }, + BufferLineBufferSelected = { fg = C.white, bg = C.bg, bold = true }, + BufferLineTab = { fg = C.grey_9, bg = C.bg }, + BufferLineTabSelected = { fg = C.fg, bg = C.bg }, + BufferLineTabClose = { fg = C.red_4, bg = C.bg }, + BufferLineIndicatorSelected = { fg = C.bg, bg = C.bg }, + BufferLineCloseButtonVisible = { fg = C.grey_10, bg = C.bg }, + BufferLineCloseButtonSelected = { fg = C.red_4, bg = C.bg }, + BufferLineModifiedVisible = { fg = C.fg, bg = C.bg }, + BufferLineModifiedSelected = { fg = C.green_2, bg = C.bg }, + BufferLineError = { fg = C.red_1, bg = C.red_1 }, + BufferLineErrorDiagnostic = { fg = C.red_1, bg = C.red_1 }, +} diff --git a/lua/default_theme/plugins/cmp.lua b/lua/default_theme/plugins/cmp.lua new file mode 100644 index 0000000..09fadcb --- /dev/null +++ b/lua/default_theme/plugins/cmp.lua @@ -0,0 +1,34 @@ +return { + CmpItemAbbr = { fg = C.fg }, + CmpItemAbbrDefault = { fg = C.fg }, + CmpItemAbbrDeprecated = { fg = C.grey_2 }, + CmpItemAbbrMatch = { fg = C.white }, + CmpItemAbbrMatchFuzzy = { fg = C.white }, + CmpItemKind = { fg = C.yellow }, + CmpItemKindClass = { link = "@type" }, + CmpItemKindColor = { link = "@constant" }, + CmpItemKindConstant = { link = "@constant" }, + CmpItemKindConstructor = { link = "@constructor" }, + CmpItemKindEnum = { link = "@type" }, + CmpItemKindEnumMember = { link = "@field" }, + CmpItemKindEvent = { link = "@type" }, + CmpItemKindField = { link = "@field" }, + CmpItemKindFile = { link = "@text.uri" }, + CmpItemKindFolder = { link = "@constant" }, + CmpItemKindFunction = { link = "@function" }, + CmpItemKindInterface = { link = "@type" }, + CmpItemKindKeyword = { link = "@keyword" }, + CmpItemKindMethod = { link = "@method" }, + CmpItemKindModule = { link = "@namespace" }, + CmpItemKindOperator = { link = "@operator" }, + CmpItemKindProperty = { link = "@property" }, + CmpItemKindReference = { link = "@type" }, + CmpItemKindSnippet = { link = "@constant" }, + CmpItemKindStruct = { link = "@type" }, + CmpItemKindText = { link = "@text" }, + CmpItemKindTypeParameter = { link = "@type" }, + CmpItemKindUnit = { link = "@constant" }, + CmpItemKindValue = { link = "@constant" }, + CmpItemKindVariable = { link = "@variable" }, + CmpItemMenuDefault = { fg = C.fg }, +} diff --git a/lua/default_theme/plugins/dapui.lua b/lua/default_theme/plugins/dapui.lua new file mode 100644 index 0000000..e5446b0 --- /dev/null +++ b/lua/default_theme/plugins/dapui.lua @@ -0,0 +1,29 @@ +return { + DapUIVariable = { fg = C.fg }, + DapUIScope = { link = "Title" }, + DapUIType = { link = "Type" }, + DapUIValue = { fg = C.red }, + DapUIModifiedValue = { fg = C.yellow_1, bold = true }, + DapUIDecoration = { fg = C.grey_1 }, + DapUIThread = { link = "String" }, + DapUIStoppedThread = { link = "Title" }, + DapUIFrameName = { link = "Normal" }, + DapUISource = { link = "Keyword" }, + DapUILineNumber = { link = "Number" }, + DapUIFloatBorder = { link = "FloatBorder" }, + DapUIWatchesEmpty = { fg = C.red_1 }, + DapUIWatchesValue = { fg = C.orange_1 }, + DapUIWatchesError = { fg = C.red_1 }, + DapUIBreakpointsPath = { link = "Title" }, + DapUIBreakpointsInfo = { fg = C.white_2 }, + DapUIBreakpointsCurrentLine = { fg = C.yellow_1, bold = true }, + DapUIBreakpointsLine = { link = "DapUILineNumber" }, + DapUIBreakpointsDisabledLine = { link = "Comment" }, + DapUIPlayPause = { fg = C.green }, + DapUIStop = { fg = C.red }, + DapUIRestart = { fg = C.yellow }, + DapUIStepOver = { fg = C.blue }, + DapUIStepInto = { fg = C.blue }, + DapUIStepBack = { fg = C.blue }, + DapUIStepOut = { fg = C.blue }, +} diff --git a/lua/default_theme/plugins/dashboard.lua b/lua/default_theme/plugins/dashboard.lua new file mode 100644 index 0000000..4aa0598 --- /dev/null +++ b/lua/default_theme/plugins/dashboard.lua @@ -0,0 +1,6 @@ +return { + DashboardHeader = { fg = C.cyan }, + DashboardShortcut = { fg = C.yellow }, + DashboardFooter = { fg = C.cyan }, + DashboardCenter = { fg = C.blue }, +} diff --git a/lua/default_theme/plugins/gitsigns.lua b/lua/default_theme/plugins/gitsigns.lua new file mode 100644 index 0000000..7c2b159 --- /dev/null +++ b/lua/default_theme/plugins/gitsigns.lua @@ -0,0 +1,7 @@ +return { + GitSignsAdd = { fg = C.green, bg = C.none }, + GitSignsChange = { fg = C.orange_1, bg = C.none }, + GitSignsDelete = { fg = C.red_1, bg = C.none }, + MoreMsg = { fg = C.green, bold = true }, + ModeMsg = { fg = C.grey, bold = true }, +} diff --git a/lua/default_theme/plugins/highlighturl.lua b/lua/default_theme/plugins/highlighturl.lua new file mode 100644 index 0000000..c69fdf0 --- /dev/null +++ b/lua/default_theme/plugins/highlighturl.lua @@ -0,0 +1 @@ +return { HighlightURL = { underline = true } } diff --git a/lua/default_theme/plugins/hop.lua b/lua/default_theme/plugins/hop.lua new file mode 100644 index 0000000..7d3b1ac --- /dev/null +++ b/lua/default_theme/plugins/hop.lua @@ -0,0 +1,6 @@ +return { + HopNextKey = { fg = C.red, bold = true }, + HopNextKey1 = { fg = C.cyan, bold = true }, + HopNextKey2 = { fg = C.blue }, + HopUnmatched = { fg = C.grey }, +} diff --git a/lua/default_theme/plugins/indent_blankline.lua b/lua/default_theme/plugins/indent_blankline.lua new file mode 100644 index 0000000..b79419a --- /dev/null +++ b/lua/default_theme/plugins/indent_blankline.lua @@ -0,0 +1,7 @@ +return { + IndentBlanklineSpaceChar = { fg = C.grey_6, nocombine = true }, + IndentBlanklineChar = { fg = C.grey_6, nocombine = true }, + IndentBlanklineContextStart = { fg = C.grey_7, underline = true }, + IndentBlanklineContextChar = { fg = C.grey_7, nocombine = true }, + IndentBlanklineSpaceCharBlankline = { fg = C.grey_6, nocombine = true }, +} diff --git a/lua/default_theme/plugins/lightspeed.lua b/lua/default_theme/plugins/lightspeed.lua new file mode 100644 index 0000000..e891d61 --- /dev/null +++ b/lua/default_theme/plugins/lightspeed.lua @@ -0,0 +1,14 @@ +return { + LightspeedLabel = { fg = C.red_3, underline = true }, + LightspeedLabelOverlapped = { fg = C.blue, underline = true }, + LightspeedLabelDistant = { fg = C.red_1, underline = true }, + LightspeedLabelDistantOverlapped = { fg = C.blue_1, underline = true }, + LightspeedShortcut = { fg = C.black, bg = C.red_3, bold = true, underline = true }, + LightspeedShortcutOverlapped = { fg = C.black, bg = C.blue, bold = true, underline = true }, + LightspeedMaskedChar = { fg = C.green_1 }, + LightspeedGreyWash = { fg = C.grey_2, bg = C.none }, + LightspeedUnlabeledMatch = { fg = C.white, bold = true }, + LightspeedOneCharMatch = { fg = C.green, bg = C.red_3, bold = true }, + LightspeedUniqueChar = { fg = C.white, bold = true }, + LightspeedPendingOpArea = { fg = C.yellow }, +} diff --git a/lua/default_theme/plugins/neo-tree.lua b/lua/default_theme/plugins/neo-tree.lua new file mode 100644 index 0000000..810e56b --- /dev/null +++ b/lua/default_theme/plugins/neo-tree.lua @@ -0,0 +1,15 @@ +return { + NeoTreeDirectoryIcon = { fg = C.blue }, + NeoTreeRootName = { fg = C.fg, bold = true }, + NeoTreeFileName = { fg = C.fg }, + NeoTreeFileIcon = { fg = C.fg }, + NeoTreeFileNameOpened = { fg = C.green }, + NeoTreeIndentMarker = { fg = C.blue_3 }, + NeoTreeGitAdded = { fg = C.green }, + NeoTreeGitConflict = { fg = C.red }, + NeoTreeGitModified = { fg = C.orange }, + NeoTreeGitUntracked = { fg = C.yellow }, + NeoTreeNormal = { bg = C.blue_2 }, + NeoTreeNormalNC = { bg = C.blue_2 }, + NeoTreeSymbolicLinkTarget = { fg = C.cyan }, +} diff --git a/lua/default_theme/plugins/notify.lua b/lua/default_theme/plugins/notify.lua new file mode 100644 index 0000000..39ccf67 --- /dev/null +++ b/lua/default_theme/plugins/notify.lua @@ -0,0 +1,25 @@ +return { + NotifyBackground = { bg = C.bg }, + NotifyERRORBorder = { fg = C.red }, + NotifyWARNBorder = { fg = C.orange_1 }, + NotifyINFOBorder = { fg = C.green }, + NotifyDEBUGBorder = { fg = C.cyan }, + NotifyTRACERBorder = { fg = C.purple }, + NotifyERRORIcon = { fg = C.red }, + NotifyWARNIcon = { fg = C.orange_1 }, + NotifyINFOIcon = { fg = C.green }, + NotifyDEBUGIcon = { fg = C.cyan }, + NotifyTRACEIcon = { fg = C.purple }, + NotifyERRORTitle = { fg = C.red }, + NotifyWARNTitle = { fg = C.orange_1 }, + NotifyINFOTitle = { fg = C.green }, + NotifyDEBUGTitle = { fg = C.cyan }, + NotifyTRACETitle = { fg = C.purple }, + NotifyERRORBody = { fg = C.fg }, + NotifyWARNBody = { fg = C.fg }, + NotifyINFOBody = { fg = C.fg }, + NotifyDEBUGBody = { fg = C.fg }, + NotifyTRACEBody = { fg = C.fg }, + NotifyLogTime = { fg = C.grey_2 }, + NotifyLogTitle = { fg = C.blue }, +} diff --git a/lua/default_theme/plugins/nvim-tree.lua b/lua/default_theme/plugins/nvim-tree.lua new file mode 100644 index 0000000..48114ff --- /dev/null +++ b/lua/default_theme/plugins/nvim-tree.lua @@ -0,0 +1,19 @@ +return { + NvimTreeFolderIcon = { fg = C.blue }, + NvimTreeExecFile = { fg = C.green }, + NvimTreeOpenedFile = { fg = C.green }, + NvimTreeRootFolder = { fg = C.bg }, + NvimTreeEndOfBuffer = { fg = C.bg }, + NvimTreeNormal = { bg = C.blue_2 }, + NvimTreeNormalNC = { bg = C.blue_2 }, + NvimTreeVertSplit = { fg = C.blue_2, bg = C.blue_2 }, + NvimTreeImageFile = { fg = C.purple }, + NvimTreeSymlink = { fg = C.cyan }, + NvimTreeSpecialFile = { fg = C.yellow }, + NvimTreeGitDeleted = { fg = C.red }, + NvimTreeGitMerge = { fg = C.orange }, + NvimTreeGitRenamed = { fg = C.purple }, + NvimTreeGitStaged = { fg = C.green }, + NvimTreeGitDirty = { fg = C.red }, + NvimTreeGitNew = { fg = C.yellow }, +} diff --git a/lua/default_theme/plugins/nvim-web-devicons.lua b/lua/default_theme/plugins/nvim-web-devicons.lua new file mode 100644 index 0000000..d76961d --- /dev/null +++ b/lua/default_theme/plugins/nvim-web-devicons.lua @@ -0,0 +1,34 @@ +return { + DevIconC = { fg = C.c }, + DevIconCss = { fg = C.css }, + DevIconDeb = { fg = C.deb }, + DevIconDockerfile = { fg = C.docker }, + DevIconHtml = { fg = C.html }, + DevIconJpeg = { fg = C.jpeg }, + DevIconJpg = { fg = C.jpg }, + DevIconJs = { fg = C.js }, + DevIconJsx = { fg = C.jsx }, + DevIconKotlin = { fg = C.kt }, + DevIconLock = { fg = C.lock }, + DevIconLua = { fg = C.lua }, + DevIconMp3 = { fg = C.mp3 }, + DevIconMp4 = { fg = C.mp4 }, + DevIconOut = { fg = C.out }, + DevIconPng = { fg = C.png }, + DevIconPy = { fg = C.py }, + DevIconRb = { fg = C.rb }, + DevIconRobots = { fg = C.robots }, + DevIconRpm = { fg = C.rpm }, + DevIconRs = { fg = C.rs }, + DevIconToml = { fg = C.toml }, + DevIconTrueTypeFont = { fg = C.ttf }, + DevIconTs = { fg = C.ts }, + DevIconVue = { fg = C.vue }, + DevIconWebOpenFontFormat = { fg = C.woff }, + DevIconWebOpenFontFormat2 = { fg = C.woff2 }, + DevIconXz = { fg = C.zip }, + DevIconZip = { fg = C.zip }, + DevIconMd = { fg = C.md }, + DevIconPackageJson = { fg = C.pkg }, + DevIconPackageLockJson = { fg = C.pkg }, +} diff --git a/lua/default_theme/plugins/rainbow.lua b/lua/default_theme/plugins/rainbow.lua new file mode 100644 index 0000000..2165c07 --- /dev/null +++ b/lua/default_theme/plugins/rainbow.lua @@ -0,0 +1,9 @@ +return { + rainbowcol1 = { fg = "Gold" }, + rainbowcol2 = { fg = "Orchid" }, + rainbowcol3 = { fg = "LightSkyBlue" }, + rainbowcol4 = { fg = "Gold" }, + rainbowcol5 = { fg = "Orchid" }, + rainbowcol6 = { fg = "LightSkyBlue" }, + rainbowcol7 = { fg = "Orchid" }, +} diff --git a/lua/default_theme/plugins/symbols_outline.lua b/lua/default_theme/plugins/symbols_outline.lua new file mode 100644 index 0000000..362e49e --- /dev/null +++ b/lua/default_theme/plugins/symbols_outline.lua @@ -0,0 +1 @@ +return { FocusedSymbol = { fg = C.yellow, bg = C.none } } diff --git a/lua/default_theme/plugins/telescope.lua b/lua/default_theme/plugins/telescope.lua new file mode 100644 index 0000000..3d0a8f0 --- /dev/null +++ b/lua/default_theme/plugins/telescope.lua @@ -0,0 +1,57 @@ +return { + TelescopeResultsTitle = { fg = C.green }, + TelescopePromptTitle = { fg = C.blue }, + TelescopePreviewTitle = { fg = C.purple }, + TelescopeResultsBorder = { fg = C.fg }, + TelescopePromptBorder = { fg = C.fg }, + TelescopePreviewBorder = { fg = C.fg }, + TelescopeSelectionCaret = { fg = C.red }, + TelescopeMatching = { fg = C.yellow }, + TelescopeSelection = { bg = C.grey_5 }, + TelescopeMultiSelection = { fg = C.blue }, + TelescopeMultiIcon = { fg = C.blue }, + TelescopeNormal = { fg = C.fg, bg = C.bg }, + TelescopePreviewNormal = { fg = C.fg, bg = C.bg }, + TelescopePromptNormal = { fg = C.fg, bg = C.bg }, + TelescopeResultsNormal = { fg = C.fg, bg = C.bg }, + TelescopeBorder = { fg = C.fg }, + TelescopeTitle = { fg = C.fg }, + TelescopePromptCounter = { fg = C.grey_1 }, + TelescopePromptPrefix = { fg = C.blue }, + TelescopePreviewLine = { bg = C.grey_5 }, + TelescopePreviewMatch = { fg = C.yellow }, + TelescopePreviewPipe = { fg = C.yellow }, + TelescopePreviewCharDev = { fg = C.yellow }, + TelescopePreviewDirectory = { fg = C.blue }, + TelescopePreviewBlock = { fg = C.yellow }, + TelescopePreviewLink = { fg = C.blue }, + TelescopePreviewSocket = { fg = C.purple }, + TelescopePreviewRead = { fg = C.yellow }, + TelescopePreviewWrite = { fg = C.purple }, + TelescopePreviewExecute = { fg = C.green }, + TelescopePreviewHyphen = { fg = C.grey_1 }, + TelescopePreviewSticky = { fg = C.blue }, + TelescopePreviewSize = { fg = C.green }, + TelescopePreviewUser = { fg = C.yellow }, + TelescopePreviewGroup = { fg = C.yellow }, + TelescopePreviewDate = { fg = C.blue }, + TelescopePreviewMessage = { fg = C.fg }, + TelescopePreviewMessageFillchar = { fg = C.fg }, + TelescopeResultsClass = { fg = C.yellow }, + TelescopeResultsConstant = { fg = C.yellow }, + TelescopeResultsField = { fg = C.red }, + TelescopeResultsFunction = { fg = C.blue }, + TelescopeResultsMethod = { fg = C.blue }, + TelescopeResultsOperator = { fg = C.cyan }, + TelescopeResultsStruct = { fg = C.purple }, + TelescopeResultsVariable = { fg = C.red }, + TelescopeResultsLineNr = { fg = C.grey_1 }, + TelescopeResultsIdentifier = { fg = C.blue }, + TelescopeResultsNumber = { fg = C.orange }, + TelescopeResultsComment = { fg = C.grey_2 }, + TelescopeResultsSpecialComment = { fg = C.grey }, + TelescopeResultsDiffChange = { fg = C.none, bg = C.yellow }, + TelescopeResultsDiffAdd = { fg = C.none, bg = C.green }, + TelescopeResultsDiffDelete = { fg = C.none, bg = C.red }, + TelescopeResultsDiffUntracked = { fg = C.none, bg = C.grey_1 }, +} diff --git a/lua/default_theme/plugins/treesitter.lua b/lua/default_theme/plugins/treesitter.lua new file mode 100644 index 0000000..66380af --- /dev/null +++ b/lua/default_theme/plugins/treesitter.lua @@ -0,0 +1,63 @@ +local treesitter = { + ["@annotation"] = { fg = C.yellow }, + ["@attribute"] = { fg = C.red }, + ["@boolean"] = { fg = C.orange }, + ["@character"] = { fg = C.green }, + ["@conditional"] = { fg = C.purple }, + ["@constant"] = { fg = C.yellow }, + ["@constant.builtin"] = { fg = C.orange }, + ["@constant.macro"] = { fg = C.red }, + ["@constant.rust"] = { fg = C.cyan }, + ["@constructor"] = { fg = C.yellow }, + ["@error"] = { fg = C.red }, + ["@exception"] = { fg = C.purple }, + ["@field"] = { fg = C.red }, + ["@float"] = { fg = C.orange }, + ["@function"] = { fg = C.blue }, + ["@function.builtin"] = { fg = C.blue }, + ["@function.macro"] = { fg = C.yellow }, + ["@function.macro.rust"] = { fg = C.orange }, + ["@include"] = { fg = C.purple }, + ["@keyword"] = { fg = C.purple }, + ["@keyword.function"] = { fg = C.purple }, + ["@keyword.function.rust"] = { fg = C.orange }, + ["@keyword.operator"] = { fg = C.purple }, + ["@label"] = { fg = C.blue }, + ["@literal.markdown"] = { fg = C.green }, + ["@method"] = { fg = C.blue }, + ["@namespace"] = { fg = C.purple }, + ["@namespace.rust"] = { fg = C.yellow }, + ["@none.markdown"] = { fg = C.fg }, + ["@number"] = { fg = C.orange }, + ["@operator"] = { fg = C.cyan }, + ["@parameter"] = { fg = C.red }, + ["@parameter.reference"] = { fg = C.cyan }, + ["@property"] = { fg = C.yellow }, + ["@punctuation.bracket"] = { fg = C.fg }, + ["@punctuation.delimiter"] = { fg = C.fg }, + ["@punctuation.delimiter.markdown"] = { fg = C.fg }, + ["@punctuation.special"] = { fg = C.fg }, + ["@punctuation.special.markdown"] = { fg = C.red }, + ["@repeat"] = { fg = C.purple }, + ["@string"] = { fg = C.green }, + ["@string.escape"] = { fg = C.red }, + ["@string.regex"] = { fg = C.green }, + ["@tag"] = { fg = C.red }, + ["@tag.delimiter"] = { fg = C.fg }, + ["@text"] = { fg = C.fg }, + ["@text.emphasis"] = { fg = C.purple, italic = true }, + ["@text.literal"] = { fg = C.fg }, + ["@text.reference"] = { fg = C.yellow }, + ["@text.strong"] = { fg = C.blue, bold = true }, + ["@text.title"] = { fg = C.fg }, + ["@text.underline"] = { fg = C.fg }, + ["@text.uri"] = { fg = C.green }, + ["@title.markdown"] = { fg = C.red }, + ["@type"] = { fg = C.blue }, + ["@type.builtin"] = { fg = C.blue }, + ["@type.rust"] = { fg = C.yellow }, + ["@variable"] = { fg = C.red }, + ["@variable.builtin"] = { fg = C.yellow }, +} + +return treesitter diff --git a/lua/default_theme/plugins/vimwiki.lua b/lua/default_theme/plugins/vimwiki.lua new file mode 100644 index 0000000..8be9dec --- /dev/null +++ b/lua/default_theme/plugins/vimwiki.lua @@ -0,0 +1,14 @@ +return { + VimwikiLink = { fg = C.cyan, bg = C.none }, + VimwikiHeaderChar = { fg = C.grey, bg = C.none }, + VimwikiHR = { fg = C.yellow, bg = C.none }, + VimwikiList = { fg = C.orange, bg = C.none }, + VimwikiTag = { fg = C.orange, bg = C.none }, + VimwikiMarkers = { fg = C.grey, bg = C.none }, + VimwikiHeader1 = { fg = C.orange, bg = C.none, bold = true }, + VimwikiHeader2 = { fg = C.green, bg = C.none, bold = true }, + VimwikiHeader3 = { fg = C.blue, bg = C.none, bold = true }, + VimwikiHeader4 = { fg = C.cyan, bg = C.none, bold = true }, + VimwikiHeader5 = { fg = C.yellow, bg = C.none, bold = true }, + VimwikiHeader6 = { fg = C.purple, bg = C.none, bold = true }, +} diff --git a/lua/default_theme/plugins/which-key.lua b/lua/default_theme/plugins/which-key.lua new file mode 100644 index 0000000..7bc6da2 --- /dev/null +++ b/lua/default_theme/plugins/which-key.lua @@ -0,0 +1,5 @@ +return { + WhichKeyFloat = { fg = C.fg }, + WhichKeyDesc = { fg = C.blue }, + WhichKeyGroup = { fg = C.blue }, +} diff --git a/lua/user_example/init.lua b/lua/user_example/init.lua new file mode 100644 index 0000000..2da5915 --- /dev/null +++ b/lua/user_example/init.lua @@ -0,0 +1,363 @@ +-- AstroNvim Configuration Table +-- All configuration changes should go inside of the table below + +-- You can think of a Lua "table" as a dictionary like data structure the +-- normal format is "key = value". These also handle array like data structures +-- where a value with no key simply has an implicit numeric key +local config = { + + -- Configure AstroNvim updates + updater = { + remote = "origin", -- remote to use + channel = "stable", -- "stable" or "nightly" + version = "latest", -- "latest", tag name, or regex search like "v1.*" to only do updates before v2 (STABLE ONLY) + branch = "main", -- branch name (NIGHTLY ONLY) + commit = nil, -- commit hash (NIGHTLY ONLY) + pin_plugins = nil, -- nil, true, false (nil will pin plugins on stable only) + skip_prompts = false, -- skip prompts about breaking changes + show_changelog = true, -- show the changelog after performing an update + auto_reload = false, -- automatically reload and sync packer after a successful update + auto_quit = false, -- automatically quit the current session after a successful update + -- remotes = { -- easily add new remotes to track + -- ["remote_name"] = "https://remote_url.come/repo.git", -- full remote url + -- ["remote2"] = "github_user/repo", -- GitHub user/repo shortcut, + -- ["remote3"] = "github_user", -- GitHub user assume AstroNvim fork + -- }, + }, + + -- Set colorscheme to use + colorscheme = "default_theme", + + -- Add highlight groups in any theme + highlights = { + -- init = { -- this table overrides highlights in all themes + -- Normal = { bg = "#000000" }, + -- } + -- duskfox = { -- a table of overrides/changes to the duskfox theme + -- Normal = { bg = "#000000" }, + -- }, + }, + + -- set vim options here (vim.. = value) + options = { + opt = { + -- set to true or false etc. + relativenumber = true, -- sets vim.opt.relativenumber + number = true, -- sets vim.opt.number + spell = false, -- sets vim.opt.spell + signcolumn = "auto", -- sets vim.opt.signcolumn to auto + wrap = false, -- sets vim.opt.wrap + }, + g = { + mapleader = " ", -- sets vim.g.mapleader + autoformat_enabled = true, -- enable or disable auto formatting at start (lsp.formatting.format_on_save must be enabled) + cmp_enabled = true, -- enable completion at start + autopairs_enabled = true, -- enable autopairs at start + diagnostics_enabled = true, -- enable diagnostics at start + status_diagnostics_enabled = true, -- enable diagnostics in statusline + icons_enabled = true, -- disable icons in the UI (disable if no nerd font is available, requires :PackerSync after changing) + ui_notifications_enabled = true, -- disable notifications when toggling UI elements + heirline_bufferline = false, -- enable new heirline based bufferline (requires :PackerSync after changing) + }, + }, + -- If you need more control, you can use the function()...end notation + -- options = function(local_vim) + -- local_vim.opt.relativenumber = true + -- local_vim.g.mapleader = " " + -- local_vim.opt.whichwrap = vim.opt.whichwrap - { 'b', 's' } -- removing option from list + -- local_vim.opt.shortmess = vim.opt.shortmess + { I = true } -- add to option list + -- + -- return local_vim + -- end, + + -- Set dashboard header + header = { + " █████ ███████ ████████ ██████ ██████", + "██ ██ ██ ██ ██ ██ ██ ██", + "███████ ███████ ██ ██████ ██ ██", + "██ ██ ██ ██ ██ ██ ██ ██", + "██ ██ ███████ ██ ██ ██ ██████", + " ", + " ███  ██ ██  ██ ██ ███  ███", + " ████  ██ ██  ██ ██ ████  ████", + " ██ ██  ██ ██  ██ ██ ██ ████ ██", + " ██  ██ ██  ██  ██  ██ ██  ██  ██", + " ██   ████   ████   ██ ██      ██", + }, + + -- Default theme configuration + default_theme = { + -- Modify the color palette for the default theme + colors = { + fg = "#abb2bf", + bg = "#1e222a", + }, + highlights = function(hl) -- or a function that returns a new table of colors to set + local C = require "default_theme.colors" + + hl.Normal = { fg = C.fg, bg = C.bg } + + -- New approach instead of diagnostic_style + hl.DiagnosticError.italic = true + hl.DiagnosticHint.italic = true + hl.DiagnosticInfo.italic = true + hl.DiagnosticWarn.italic = true + + return hl + end, + -- enable or disable highlighting for extra plugins + plugins = { + aerial = true, + beacon = false, + bufferline = true, + cmp = true, + dashboard = true, + highlighturl = true, + hop = false, + indent_blankline = true, + lightspeed = false, + ["neo-tree"] = true, + notify = true, + ["nvim-tree"] = false, + ["nvim-web-devicons"] = true, + rainbow = true, + symbols_outline = false, + telescope = true, + treesitter = true, + vimwiki = false, + ["which-key"] = true, + }, + }, + + -- Diagnostics configuration (for vim.diagnostics.config({...})) when diagnostics are on + diagnostics = { + virtual_text = true, + underline = true, + }, + + -- Extend LSP configuration + lsp = { + -- enable servers that you already have installed without mason + servers = { + -- "pyright" + }, + formatting = { + -- control auto formatting on save + format_on_save = { + enabled = true, -- enable or disable format on save globally + allow_filetypes = { -- enable format on save for specified filetypes only + -- "go", + }, + ignore_filetypes = { -- disable format on save for specified filetypes + -- "python", + }, + }, + disabled = { -- disable formatting capabilities for the listed language servers + -- "sumneko_lua", + }, + timeout_ms = 1000, -- default format timeout + -- filter = function(client) -- fully override the default formatting function + -- return true + -- end + }, + -- easily add or disable built in mappings added during LSP attaching + mappings = { + n = { + -- ["lf"] = false -- disable formatting keymap + }, + }, + -- add to the global LSP on_attach function + -- on_attach = function(client, bufnr) + -- end, + + -- override the mason server-registration function + -- server_registration = function(server, opts) + -- require("lspconfig")[server].setup(opts) + -- end, + + -- Add overrides for LSP server settings, the keys are the name of the server + ["server-settings"] = { + -- example for addings schemas to yamlls + -- yamlls = { -- override table for require("lspconfig").yamlls.setup({...}) + -- settings = { + -- yaml = { + -- schemas = { + -- ["http://json.schemastore.org/github-workflow"] = ".github/workflows/*.{yml,yaml}", + -- ["http://json.schemastore.org/github-action"] = ".github/action.{yml,yaml}", + -- ["http://json.schemastore.org/ansible-stable-2.9"] = "roles/tasks/*.{yml,yaml}", + -- }, + -- }, + -- }, + -- }, + }, + }, + + -- Mapping data with "desc" stored directly by vim.keymap.set(). + -- + -- Please use this mappings table to set keyboard mapping since this is the + -- lower level configuration and more robust one. (which-key will + -- automatically pick-up stored data by this setting.) + mappings = { + -- first key is the mode + n = { + -- second key is the lefthand side of the map + -- mappings seen under group name "Buffer" + ["bb"] = { "tabnew", desc = "New tab" }, + ["bc"] = { "BufferLinePickClose", desc = "Pick to close" }, + ["bj"] = { "BufferLinePick", desc = "Pick to jump" }, + ["bt"] = { "BufferLineSortByTabs", desc = "Sort by tabs" }, + -- quick save + -- [""] = { ":w!", desc = "Save File" }, -- change description but the same command + }, + t = { + -- setting a mapping to false will disable it + -- [""] = false, + }, + }, + + -- Configure plugins + plugins = { + init = { + -- You can disable default plugins as follows: + -- ["goolord/alpha-nvim"] = { disable = true }, + + -- You can also add new plugins here as well: + -- Add plugins, the packer syntax without the "use" + -- { "andweeb/presence.nvim" }, + -- { + -- "ray-x/lsp_signature.nvim", + -- event = "BufRead", + -- config = function() + -- require("lsp_signature").setup() + -- end, + -- }, + + -- We also support a key value style plugin definition similar to NvChad: + -- ["ray-x/lsp_signature.nvim"] = { + -- event = "BufRead", + -- config = function() + -- require("lsp_signature").setup() + -- end, + -- }, + }, + -- All other entries override the require("").setup({...}) call for default plugins + ["null-ls"] = function(config) -- overrides `require("null-ls").setup(config)` + -- config variable is the default configuration table for the setup function call + -- local null_ls = require "null-ls" + + -- Check supported formatters and linters + -- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/formatting + -- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/diagnostics + config.sources = { + -- Set a formatter + -- null_ls.builtins.formatting.stylua, + -- null_ls.builtins.formatting.prettier, + } + return config -- return final config table + end, + treesitter = { -- overrides `require("treesitter").setup(...)` + -- ensure_installed = { "lua" }, + }, + -- use mason-lspconfig to configure LSP installations + ["mason-lspconfig"] = { -- overrides `require("mason-lspconfig").setup(...)` + -- ensure_installed = { "sumneko_lua" }, + }, + -- use mason-null-ls to configure Formatters/Linter installation for null-ls sources + ["mason-null-ls"] = { -- overrides `require("mason-null-ls").setup(...)` + -- ensure_installed = { "prettier", "stylua" }, + }, + ["mason-nvim-dap"] = { -- overrides `require("mason-nvim-dap").setup(...)` + -- ensure_installed = { "python" }, + }, + }, + + -- LuaSnip Options + luasnip = { + -- Extend filetypes + filetype_extend = { + -- javascript = { "javascriptreact" }, + }, + -- Configure luasnip loaders (vscode, lua, and/or snipmate) + vscode = { + -- Add paths for including more VS Code style snippets in luasnip + paths = {}, + }, + }, + + -- CMP Source Priorities + -- modify here the priorities of default cmp sources + -- higher value == higher priority + -- The value can also be set to a boolean for disabling default sources: + -- false == disabled + -- true == 1000 + cmp = { + source_priority = { + nvim_lsp = 1000, + luasnip = 750, + buffer = 500, + path = 250, + }, + }, + + -- Customize Heirline options + heirline = { + -- -- Customize different separators between sections + -- separators = { + -- tab = { "", "" }, + -- }, + -- -- Customize colors for each element each element has a `_fg` and a `_bg` + -- colors = function(colors) + -- colors.git_branch_fg = astronvim.get_hlgroup "Conditional" + -- return colors + -- end, + -- -- Customize attributes of highlighting in Heirline components + -- attributes = { + -- -- styling choices for each heirline element, check possible attributes with `:h attr-list` + -- git_branch = { bold = true }, -- bold the git branch statusline component + -- }, + -- -- Customize if icons should be highlighted + -- icon_highlights = { + -- breadcrumbs = false, -- LSP symbols in the breadcrumbs + -- file_icon = { + -- winbar = false, -- Filetype icon in the winbar inactive windows + -- statusline = true, -- Filetype icon in the statusline + -- }, + -- }, + }, + + -- Modify which-key registration (Use this with mappings table in the above.) + ["which-key"] = { + -- Add bindings which show up as group name + register = { + -- first key is the mode, n == normal mode + n = { + -- second key is the prefix, prefixes + [""] = { + -- third key is the key to bring up next level and its displayed + -- group name in which-key top level menu + ["b"] = { name = "Buffer" }, + }, + }, + }, + }, + + -- This function is run last and is a good place to configuring + -- augroups/autocommands and custom filetypes also this just pure lua so + -- anything that doesn't fit in the normal config locations above can go here + polish = function() + -- Set up custom filetypes + -- vim.filetype.add { + -- extension = { + -- foo = "fooscript", + -- }, + -- filename = { + -- ["Foofile"] = "fooscript", + -- }, + -- pattern = { + -- ["~/%.config/foo/.*"] = "fooscript", + -- }, + -- } + end, +} + +return config diff --git a/pack/github/start/copilot.vim b/pack/github/start/copilot.vim new file mode 160000 index 0000000..8c84164 --- /dev/null +++ b/pack/github/start/copilot.vim @@ -0,0 +1 @@ +Subproject commit 8c8416488ef21483dd5d2922ea194c05e9a3baaf diff --git a/packer_snapshot b/packer_snapshot new file mode 100644 index 0000000..8b78b38 --- /dev/null +++ b/packer_snapshot @@ -0,0 +1 @@ +{"better-escape.nvim": {"commit": "6fed338"}, "nvim-dap": {"commit": "700a3c7"}, "telescope-fzf-native.nvim": {"commit": "fab3e22"}, "packer.nvim": {"commit": "dac4088"}, "nvim-notify": {"commit": "b005821"}, "mason-null-ls.nvim": {"commit": "c4b4a6f"}, "nvim-lspconfig": {"commit": "7b98aad"}, "smart-splits.nvim": {"commit": "fdd158c"}, "nvim-window-picker": {"commit": "5902827"}, "null-ls.nvim": {"commit": "9155589"}, "mason-lspconfig.nvim": {"commit": "3751eb5"}, "which-key.nvim": {"commit": "68bacb6"}, "bufferline.nvim": {"commit": "c7492a7"}, "nvim-autopairs": {"commit": "f00eb3b"}, "neovim-session-manager": {"commit": "f8c85da"}, "friendly-snippets": {"commit": "484fb38"}, "nvim-colorizer.lua": {"commit": "760e27d"}, "lspkind.nvim": {"commit": "c68b3a0"}, "gitsigns.nvim": {"commit": "c6f45cc"}, "SchemaStore.nvim": {"commit": "3c255ca"}, "indent-blankline.nvim": {"commit": "c4c203c"}, "dressing.nvim": {"commit": "4436d6f"}, "nvim-ts-autotag": {"commit": "fdefe46"}, "neo-tree.nvim": {"commit": "3b41f0d"}, "telescope.nvim": {"commit": "e8c01ba"}, "nvim-ts-context-commentstring": {"commit": "4a42b30"}, "Comment.nvim": {"commit": "e89df17"}, "mason.nvim": {"commit": "c609775"}, "aerial.nvim": {"commit": "3eafbd2"}, "alpha-nvim": {"commit": "21a0f25"}, "cmp-nvim-lsp": {"commit": "5922477"}, "LuaSnip": {"commit": "5d57303"}, "nvim-dap-ui": {"commit": "b0612c9"}, "heirline.nvim": {"commit": "556666a"}, "nvim-web-devicons": {"commit": "6c38926"}, "cmp_luasnip": {"commit": "1809552"}, "nvim-treesitter": {"commit": "be0b3ba1"}, "nui.nvim": {"commit": "257da38"}, "impatient.nvim": {"commit": "c90e273"}, "indent-o-matic": {"commit": "749b7cb"}, "mason-nvim-dap.nvim": {"commit": "d6cb770"}, "toggleterm.nvim": {"commit": "b02a167"}, "plenary.nvim": {"commit": "1c7e3e6"}, "bufdelete.nvim": {"commit": "f79e9d1"}, "nvim-cmp": {"commit": "a9c701f"}, "nvim-ts-rainbow": {"commit": "ef95c15"}, "cmp-path": {"commit": "91ff86c"}, "cmp-buffer": {"commit": "3022dbc"}}